解析搜索字符串(例如:您在搜索引擎中输入的内容)为可评估的表达式。
您调用 Parser.parse(searchString:)
。这会返回已解析的表达式组合的树状结构。您可以询问 Expression
对象它是否与给定的“haystack”(例如要搜索的文本)匹配,例如:
import SearchExpressionParser
guard let expr = try? Parser.parse(searchString: "Hello") else { fatalError() }
expr.isSatisfied(by: "Hello World!") // true
空搜索字符串会被评估为匹配任何内容的通配符。
为了在应用程序中有效地使用搜索表达式,我发现对文本的全部小写表示形式进行操作并使用 C 的 strstr
非常有益。
因此,例如在笔记应用程序中,您应该考虑将笔记在内存中转换为小写,然后使用 C 字符串比较来进行表达式匹配。
首先,让您的文本实现 CStringExpressionSatisfiable
协议
struct Note {
let text: String
private let cString: [CChar]
init(text: String) {
self.text = text
self.cString = text
// Favor simple over grapheme cluster characters
.precomposedStringWithCanonicalMapping
.cString(using: .utf8)!
}
}
import SearchExpressionParser
extension Note: CStringExpressionSatisfiable {
func matches(needle: [CChar]) -> Bool {
return strstr(self.cString, needle) != nil
}
}
然后将此对象传递给表达式。
let warAndPeace = Note(String(contentsOf: "books/Tolstoy/War-and-Peace.txt"))
let protagonist = try! Parser.parse(searchString: "\"Pierre Bezukhov\" OR \"Pyotr Kirillovich\"")
protagonist.isSatisfied(by: warAndPeace) // true
遗憾的是,这会将实现匹配算法的负担放在您这边,但这是设计使然,以便您保留 C 字符串,而不是依赖框架为您即时转换文本——因为那样做毫无用处。与常规的 String.contains
匹配相比,这种速度提升非常值得付出几行代码的代价,后者在涉及 Emoji 表情符号时甚至会变得更慢。
运算符均为大写:AND
、OR
、NOT
/!
。
foo bar baz
等同于 foo AND bar AND baz
NOT b
等于 !b
! b
(注意空格)是 ! AND b
"!b"
是对 "!b" 的短语搜索,匹配字面上的感叹号\!b
hello "you \"lovely\" specimen"
\AND
。请注意,小写的 "and" 不会被视为运算符,只有大写形式才会被视为运算符。您可以使用括号将表达式分组
!(foo OR (baz AND !bar))
... 当然,等同于
!foo OR !baz AND !foo OR !bar
到目前为止,还没有真正的运算符优先级实现,因为我在其中使用此功能的全文搜索上下文不需要它。
此嵌套项的 Expression
对象看起来像这样
// !(foo OR (baz AND !bar))
NotNode(
OrNode(lhs: ContainsNode("foo"),
rhs: AndNode(lhs: ContainsNode("baz"),
rhs: NotNode(ContainsNode("bar")))))
当您调用高级入口点 Parser.parse(searchString:)
时,您会获得一个符合 Expression
的对象作为返回值。
Expression
协议是
public protocol Expression {
func isSatisfied(by satisfiable: StringExpressionSatisfiable) -> Bool
func isSatisfied(by satisfiable: CStringExpressionSatisfiable) -> Bool
}
您可以将“haystack”传递给 isStatisfied
,例如您要搜索的文本。
当单词的大小写无关紧要时,请记住,如果您让要搜索的文本符合 CStringExpressionSatisfiable
并传递那个对象,速度会快得多。有关详细信息,请参见上文。
提供的表达式有
AnythingNode
将匹配您放入的任何内容;它是通配符或空搜索。ContainsNode
表示类似于 String.contains
的检查。NotNode
包装 1 个其他节点并反转其结果。AndNode
和 OrNode
都接受 2 个其他节点,并使用布尔运算符等价物组合它们的结果。在您的应用程序中使用它?打开一个 PR 并告诉世界!
版权所有 (c) 2018-2019 Christian Tietze。根据 MIT 许可证分发。