Pachyderm: Add CharacterCounter
This commit is contained in:
parent
5a7d7711bc
commit
ad83e3a9f7
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// CharacterCounter.swift
|
||||
// Pachyderm
|
||||
//
|
||||
// Created by Shadowfacts on 9/29/18.
|
||||
// Copyright © 2018 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct CharacterCounter {
|
||||
|
||||
static let linkDetector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
|
||||
static let mention = try! NSRegularExpression(pattern: "(@[a-z0-9_]+)(?:@[a-z0-9\\-\\.]+[a-z0-9]+)?", options: .caseInsensitive)
|
||||
|
||||
public static func count(text: String) -> Int {
|
||||
let mentionsRemoved = removeMentions(in: text)
|
||||
var count = mentionsRemoved.count
|
||||
for match in linkDetector.matches(in: mentionsRemoved, options: [], range: NSRange(location: 0, length: mentionsRemoved.utf16.count)) {
|
||||
count -= match.range.length
|
||||
count += 23 // Mastodon link length
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
private static func removeMentions(in text: String) -> String {
|
||||
var mut = text
|
||||
for match in mention.matches(in: mut, options: [], range: NSRange(location: 0, length: mut.utf16.count)).reversed() {
|
||||
let replacement = mut[Range(match.range(at: 1), in: mut)!]
|
||||
mut.replaceSubrange(Range(match.range, in: mut)!, with: replacement)
|
||||
}
|
||||
return mut
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// CharacterCounterTests.swift
|
||||
// PachydermTests
|
||||
//
|
||||
// Created by Shadowfacts on 9/29/18.
|
||||
// Copyright © 2018 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Pachyderm
|
||||
|
||||
class CharacterCounterTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
}
|
||||
|
||||
func testCountPlainText() {
|
||||
XCTAssertEqual(CharacterCounter.count(text: "This is an example message"), 26)
|
||||
XCTAssertEqual(CharacterCounter.count(text: "This is an example message with an Emoji: 😄"), 43)
|
||||
XCTAssertEqual(CharacterCounter.count(text: "😄😄😄😄😄😄😄"), 7)
|
||||
}
|
||||
|
||||
func testCountLinks() {
|
||||
XCTAssertEqual(CharacterCounter.count(text: "This is an example with a link: https://example.com"), 55)
|
||||
XCTAssertEqual(CharacterCounter.count(text: "This is an example with a link 😄: https://example.com"), 57)
|
||||
XCTAssertEqual(CharacterCounter.count(text: "😄😄😄😄😄😄😄: https://example.com"), 32)
|
||||
XCTAssertEqual(CharacterCounter.count(text: "This is an example with a link: https://a.much.longer.example.com/link?foo=bar#baz"), 55)
|
||||
}
|
||||
|
||||
func testCountLocalMentions() {
|
||||
XCTAssertEqual(CharacterCounter.count(text: "hello @example"), 14)
|
||||
XCTAssertEqual(CharacterCounter.count(text: "@some_really_long_name"), 22)
|
||||
}
|
||||
|
||||
func testCountRemoteMentions() {
|
||||
XCTAssertEqual(CharacterCounter.count(text: "hello @example@some.remote.social"), 14)
|
||||
XCTAssertEqual(CharacterCounter.count(text: "hello @some_really_long_name@some-long.remote-instance.social"), 28)
|
||||
}
|
||||
|
||||
}
|
|
@ -109,6 +109,8 @@
|
|||
D6D4DDDA212518A200E1C4BB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6D4DDD8212518A200E1C4BB /* LaunchScreen.storyboard */; };
|
||||
D6D4DDE5212518A200E1C4BB /* TuskerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDE4212518A200E1C4BB /* TuskerTests.swift */; };
|
||||
D6D4DDF0212518A200E1C4BB /* TuskerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDEF212518A200E1C4BB /* TuskerUITests.swift */; };
|
||||
D6E6F26321603F8B006A8599 /* CharacterCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26221603F8B006A8599 /* CharacterCounter.swift */; };
|
||||
D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26421604242006A8599 /* CharacterCounterTests.swift */; };
|
||||
D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */; };
|
||||
D6F953EE21251A0700CF0F2B /* Timeline.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6F953ED21251A0700CF0F2B /* Timeline.storyboard */; };
|
||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EF21251A2900CF0F2B /* MastodonController.swift */; };
|
||||
|
@ -276,6 +278,8 @@
|
|||
D6D4DDEB212518A200E1C4BB /* TuskerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TuskerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D6D4DDEF212518A200E1C4BB /* TuskerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TuskerUITests.swift; sourceTree = "<group>"; };
|
||||
D6D4DDF1212518A200E1C4BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D6E6F26221603F8B006A8599 /* CharacterCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounter.swift; sourceTree = "<group>"; };
|
||||
D6E6F26421604242006A8599 /* CharacterCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounterTests.swift; sourceTree = "<group>"; };
|
||||
D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = "<group>"; };
|
||||
D6F953ED21251A0700CF0F2B /* Timeline.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Timeline.storyboard; sourceTree = "<group>"; };
|
||||
D6F953EF21251A2900CF0F2B /* MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonController.swift; sourceTree = "<group>"; };
|
||||
|
@ -330,6 +334,7 @@
|
|||
D61099AE2144B0CC00432DC2 /* Info.plist */,
|
||||
D61099C82144B13C00432DC2 /* Client.swift */,
|
||||
D6109A0A2145953C00432DC2 /* ClientModel.swift */,
|
||||
D6E6F26221603F8B006A8599 /* CharacterCounter.swift */,
|
||||
D61099D72144B74500432DC2 /* Extensions */,
|
||||
D61099CC2144B2C300432DC2 /* Request */,
|
||||
D61099DA2144BDB600432DC2 /* Response */,
|
||||
|
@ -342,6 +347,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D61099BA2144B0CC00432DC2 /* PachydermTests.swift */,
|
||||
D6E6F26421604242006A8599 /* CharacterCounterTests.swift */,
|
||||
D61099BC2144B0CC00432DC2 /* Info.plist */,
|
||||
);
|
||||
path = PachydermTests;
|
||||
|
@ -911,6 +917,7 @@
|
|||
D6109A11214607D500432DC2 /* Timeline.swift in Sources */,
|
||||
D61099E7214561FF00432DC2 /* Attachment.swift in Sources */,
|
||||
D61099D02144B2D700432DC2 /* Method.swift in Sources */,
|
||||
D6E6F26321603F8B006A8599 /* CharacterCounter.swift in Sources */,
|
||||
D61099FB214569F600432DC2 /* Report.swift in Sources */,
|
||||
D61099F92145698900432DC2 /* Relationship.swift in Sources */,
|
||||
D61099E12144C1DC00432DC2 /* Account.swift in Sources */,
|
||||
|
@ -939,6 +946,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */,
|
||||
D61099BB2144B0CC00432DC2 /* PachydermTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
Loading…
Reference in New Issue