Pachyderm: Add CharacterCounter

This commit is contained in:
Shadowfacts 2018-09-29 21:16:45 -04:00
parent 27fa041975
commit 7bde7c42e6
3 changed files with 86 additions and 0 deletions

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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;