SwiftScanner

Build Status codecov Platform Platform Language: Swift CocoaPods Carthage

SwiftScanner

SwiftScanner 是一个纯 Swift 实现的字符串扫描器;它没有依赖项,完全支持 Unicode(谁不喜欢 emoji 呢?),拥有许多有用的功能,并且以 Swift 为中心而设计。StringScanner 是内置的 Apple NSScanner 的一个很好的替代品。

★★ 给我们的 Github 仓库点个 Star 来帮助我们吧! ★★

相关项目

我还致力于其他几个你可能喜欢的项目。看看下面

描述
SwiftDate 在 Swift 中管理日期/时区的最佳方式
Hydra 编写更好的异步代码:async/await & promises
FlowKit 一种新的表格管理声明式方法。忘记 datasource & delegates。
SwiftRichString Swift 中优雅且轻松的 NSAttributedString
SwiftLocation 高效的定位管理器
SwiftMsgPack 快速/高效的 msgPack 编码器/解码器

主要特性

SwiftScanner 使用字符串初始化,并维护一个内部索引,用于使用两个主要概念在字符串中前后导航

这些操作的结果返回收集的字符串或索引。如果由于错误(例如,eofnotFoundinvalidInt...)操作失败,则会抛出异常,采用纯 Swift 风格。

API 文档

其他

scan 函数

#### `func scanChar() throws -> UnicodeScalar` `scanChar` allows you to scan the next character after the current's scanner `position` and return it as `UnicodeScalar`. If operation succeded internal scanner's `position` is advanced by 1 character (as unicode). If operation fails an exception is thrown.

Example:

let scanner = StringScanner("Hello this is SwiftScanner") let firstChar = try! scanner.scanChar() // get 'H'
#### `func scanInt() throws -> Int` Scan the next integer value after the current scanner's `position`; consume scalars from {0...9} until a non numeric value is encountered. Return the integer representation in base 10. Throw `.invalidInt` if scalar at current position is not in allowed range (may also return `.eof`). If operation succeded internal scanner's `position` is advanced by the number of character which represent an integer. If operation fails an exception is thrown.

Example:

let scanner = StringScanner("15 apples") let parsedInt = try! scanner.scanInt() // get Int=15
#### `func scanFloat() throws -> Float` Scan for a float value (in format ##.##) and convert it to a valid Floast. If scan succeded scanner's `position` is updated at the end of the represented string, otherwise an exception (`.invalidFloat`, `.eof`) is thrown and index is not touched.

Example:

let scanner = StringScanner("45.54 $") let parsedFloat = try! scanner.scanFloat() // get Int=45.54
#### `func scanHexInt(digits: BitDigits) throws -> Int` Scan an HEX digit expressed in these formats:

If scan succeded scanner's position is updated at the end of the represented string, otherwise an exception ((.notFound, ).invalidHex, .eof) is thrown and index is not touched.

Example:

let scanner = StringScanner("#1602") let value = try! scanner.scanHexInt(.bit16) // get Int=5634 let scanner = StringScanner("#0x0929") let value = try! scanner.scanHexInt(.bit16) // get Int=2345 let scanner = StringScanner("#0x0000000000564534") let value = try! scanner.scanHexInt(.bit64) // get Int=5653812
#### `public func scan(upTo char: UnicodeScalar) throws -> String?` Scan until given character is found starting from current scanner `position` till the end of the source string. Scanner's `position` is updated only if character is found and set just before it. Throw an exception if `.eof` is reached or `.notFound` if char was not found (in this case scanner's position is not updated)

Example:

let scanner = StringScanner("Hello <bold>Daniele</bold>") let partialString = try! scanner.scan(upTo: "<bold>") // get "Hello "
#### `func scan(upTo charSet: CharacterSet) throws -> String?` Scan until given character's is found. Index is reported before the start of the sequence, scanner's `position` is updated only if sequence is found. Throw an exception if `.eof` is reached or `.notFound` if sequence was not found.

Example:

let scanner = StringScanner("Hello, I've at least 15 apples") let partialString = try! scanner.scan(upTo: CharacterSet.decimalDigits) // get "Hello, I've at least "
#### `func scan(untilIn charSet: CharacterSet) throws -> String?` Scan, starting from scanner's `position` until the next character of the scanner is contained into given character set. Scanner's `position` is updated automatically at the end of the sequence if validated, otherwise it will not touched.

Example:

let scanner = StringScanner("HELLO i'm mark") let partialString = try! scanner.scan(untilIn: CharacterSet.lowercaseLetters) // get "HELLO"
#### `func scan(upTo string: String) throws -> String?` Scan, starting from scanner's `position` until specified string is encountered. Scanner's `position` is updated automatically at the end of the sequence if validated, otherwise it will not touched.

Example:

let scanner = StringScanner("This is a simple test I've made") let partialString = try! scanner.scan(upTo: "I've") // get "This is a simple test "
#### `func scan(untilTrue test: ((UnicodeScalar) -> (Bool))) -> String` Scan and consume at the scalar starting from current `position`, testing it with function test. If test returns `true`, the `position` increased. If `false`, the function returns.

Example:

let scanner = StringScanner("Never be satisfied 💪 and always push yourself! 😎 Do the things people say cannot be done") let delimiters = CharacterSet(charactersIn: "💪😎") while !scanner.isAtEnd { let block = scanner.scan(untilTrue: { char in return (delimiters.contains(char) == false) }) // Print: // "Never be satisfied " (first iteration) // "and always push yourself!" (second iteration) // "Do the things people say cannot be done" (third iteration) print("Block: \(block)") try scanner.skip() // push over the character }
#### `func scan(length: Int=1) -> String` Read next length characters and accumulate it If operation is succeded scanner's `position` are updated according to consumed scalars. If fails an exception is thrown and `position` is not updated.

Example:

let scanner = StringScanner("Never be satisfied") let partialString = scanner.scan(5) // "Never"

peek 函数

Peek 函数与 scan() 的概念相同,只是它不更新内部扫描器的 position 索引。 这些函数通常只返回匹配模式的 起始索引

#### `func peek(upTo char: UnicodeScalar) -> String.UnicodeScalarView.Index` 从当前扫描器的 `position` 开始,窥视直到找到字符。 扫描器的 `position` 永远不会更新。 如果到达 `.eof` 或未找到 char,则抛出 `.notFound` 异常。

例子:

let scanner = StringScanner("Never be satisfied") let index = try! scanner.peek(upTo: "b") // return 6
#### `func peek(upTo charSet: CharacterSet) -> String.UnicodeScalarView.Index` 窥视直到遇到由 set 指定的其中一个字符。 索引在序列开始之前报告,但扫描器的 `position` 永远不会更新。 如果到达 .eof 或未找到序列,则抛出异常

例子:

let scanner = StringScanner("You are in queue: 123 is your position") let index = try! scanner.peek(upTo: CharacterSet.decimalDigits) // return 18
#### `func peek(untilIn charSet: CharacterSet) -> String.UnicodeScalarView.Index` 窥视直到扫描器的下一个字符包含在给定字符集中。扫描器的 `position` 永远不会更新。

例子:

let scanner = StringScanner("654 apples") let index = try! scanner.peek(untilIn: CharacterSet.decimalDigits) // return 3
#### `func peek(upTo string: String) -> String.UnicodeScalarView.Index` 迭代直到遇到指定的字符串,而不更新索引。 扫描器的 `position` 永远不会更新,但它会报告刚好在找到的出现之前的索引。

例子:

let scanner = StringScanner("654 apples in the bug") let index = try! scanner.peek(upTo: "in") // return 11
#### `func peek(untilTrue test: ((UnicodeScalar) -> (Bool))) -> String.UnicodeScalarView.Index` 窥视当前位置的标量,并使用函数 test 对其进行测试。 它只是窥视,因此在操作结束时不会增加当前的扫描器 `position`

例子:

let scanner = StringScanner("I'm very 💪 and 😎 Go!") let delimiters = CharacterSet(charactersIn: "💪😎") while !scanner.isAtEnd { let prevIndex = scanner.position let finalIndex = scanner.peek(untilTrue: { char in return (delimiters.contains(char) == false) }) // Distance will return: // - 9 (first iteration) // - 5 (second iteration) // - 4 (third iteration) let distance = scanner.string.distance(from: prevIndex, to: finalIndex) try scanner.skip(length: distance + 1) }

其他函数

#### `func match(_ char: UnicodeScalar) -> Bool` 如果当前位置的标量与给定的标量不匹配,则返回 false。如果匹配,则将扫描器的 `position` 前进到匹配结束的位置。
let scanner = StringScanner("💪 and 😎") let match = scanner.match("😎") // return false
#### `func match(_ match: String) -> Bool` 如果从当前位置开始的标量与给定字符串中的标量不匹配,则返回 false。如果匹配,则将扫描器的 `position` 前进到匹配字符串的结束位置。
let scanner = StringScanner("I'm very 💪 and 😎 Go!") scanner.match("I'm very") // return true
#### `func reset()` 将扫描器的内部 `position` 移动到字符串的开头。 #### `func peekAtEnd()` 移动到索引的结束索引。 #### `func skip(length: Int = 1) throws` 尝试将扫描器的位置前进指定长度。如果操作不可行(到达字符串末尾),则抛出错误,并且扫描器当前的 `position` 不会更改。如果操作成功,则更新扫描器的 `position`。 #### `func back(length: Int = 1) throws` 尝试将位置后退指定长度。如果操作失败,扫描器的 `position` 不会被触及。如果操作成功,则扫描器的 `position` 根据新值进行修改。 ## 安装 您可以使用 CocoaPods、Carthage 和 Swift 包管理器安装 Swiftline。

CocoaPods

use_frameworks!
pod 'SwiftScanner'

Carthage

github 'malcommac/SwiftScanner'

Swift 包管理器

在您的 Package.swift 中将 swiftline 添加为依赖项。

  import PackageDescription

  let package = Package(name: "YourPackage",
    dependencies: [
      .Package(url: "https://github.com/malcommac/SwiftScanner.git", majorVersion: 0),
    ]
  )
## 测试 测试可以在[这里](https://github.com/malcommac/SwiftScanner/tree/master/Tests)找到。

使用以下命令运行它们:

swift test 
## 要求

当前版本兼容:

## 鸣谢 & 许可 SwiftScanner 由 [Daniele Margutti](http://www.danielemargutti.com/) 拥有和维护。

作为开源创作,欢迎任何帮助!

此库的代码在 MIT 许可证下获得许可;您可以在商业产品中使用它,没有任何限制。

唯一的要求是在您的“鸣谢/关于”部分添加一行,内容如下:

Portions SwiftScanner - http://github.com/malcommac/SwiftScanner Created by Daniele Margutti and licensed under MIT License.