【问题标题】:How to capture a word boundary in Swift NSRegularExpression?如何在 Swift NSRegularExpression 中捕获单词边界?
【发布时间】:2021-08-20 18:30:08
【问题描述】:

我想在一个以某个前缀开头的字符串中捕获所有单词。例如所有以t开头的单词

if let regex = try? NSRegularExpression(pattern: #"t[^ ]+"#, options: NSRegularExpression.Options.caseInsensitive) {
    let input = "this is the best test"
    let matches = regex.matches(in: input, options: [], range: NSRange(location: 0, length: input.count))
        
    for match in matches {
        print((input as NSString).substring(with: match.range))
    }
}

在上面的代码中,我使用了一个简单的空格作为分隔符 (#"t[^ ]+"#),并且输出符合预期:

this
the
test

但是,不仅应考虑空格,还应考虑所有单词边界。所以我用\b 替换空格以匹配所有边界(#"t[^\b]+"#)。但是,这不起作用:

this is the 
t test

似乎这段代码不寻找单词边界,而简单地寻找b...这是为什么呢?

我认为在正则表达式之前和之后使用# 会创建一个原始字符串,从而将\ 正确传递给正则表达式系统。所以#"t[^\b]+"# 应该和"t[^\\b]+" 一样,并被翻译成t[^\b]+,不是吗?

或者是单词边界运算符\b 在 Swift 正则表达式中不可用?

编辑:

根据ICU Documentation \b 匹配单词边界,因此[^\b](除单词边界外的任何内容)不应与[^b](除ab外的任何内容)相同,应该吗?

不过,\b 好像不能成套使用,可以吗?但是\B应该做同样的事情(除了单词边界之外的任何东西)。

所以我尝试改用#"t\B+"#。但是,这根本找不到任何匹配项。

问题依旧:如何在 Swift NSRegularExpression 中匹配单词边界?

【问题讨论】:

  • 你的意思是你需要pattern: #"t\w+"#
  • 如果您将t[^\b]+ 放入正则表达式在线工具中,它真的能显示您想要的吗?你的意思是\s 而不是\b?或者\w+
  • 不相关但不要在 Swift 中使用 NSStringNSRange(location:length:)。有(更可靠的)原生 API
  • @WiktorStribiżew #"t\w+"#t123 不匹配。我想匹配所有以 t 开头的单词,其中“单词”是由单词边界分隔的东西。 @Larme \b 应根据 ICU 文档匹配单词边界,其中 \s 仅匹配空格。
  • \b 匹配 - 检测 - 仅在字符类之外的单词边界。在其中,它在不同的正则表达式引擎/编程语言中表现不同。在 ICU 正则表达式中,[\b] 匹配一个 b 而不是一个退格 (\x08) 字符,就像在许多其他正则表达式风格中一样,ICU 是一个非常特殊的正则表达式库,关于这种正则表达式风格还有很多奇怪的事情(例如裸 POSIX 字符类支持。)

标签: swift regex nsregularexpression


【解决方案1】:

#"t[^\b]+"# 字符串文字会生成 t[^\b]+ 正则表达式,它仅匹配 t 和一个或多个除 b 字符之外的字符([^\b] 等于 ICU 正则表达式中的 [^b]味道)。

要匹配t,然后是一个或多个单词字符(即直到下一个最左边的单词边界),您可以使用

pattern: #"t\w+"#

\w+ 将匹配一个或多个单词字符。

[...] 是一个字符集/类。字符类旨在匹配字符\b是一个字边界只在一个字符类之外,因为一个字边界不是一个字符,它是一个零宽度的断言,匹配某个在字符串中的位置。所有零宽度断言在字符类中都失去了它们特殊的“零宽度”含义。 [.$] 并不意味着 . 或字符串结尾,它匹配 .$ 字符。 [.\z] 不匹配 . 或字符串的末尾,它匹配 .z,因为 \ 被省略,因为 \z 不是有效的转义序列。

另外,t\B+ 没有什么意义,因为\B 也是一个零宽度断言,匹配字符串中不是单词边界的 位置位置。请注意,零宽度断言不消耗文本,即没有文本被添加到整个匹配内存缓冲区,并且正则表达式索引保持在尝试零宽度断言模式之前的位置。通过在\B 之后添加+,您只需告诉正则表达式引擎匹配t 之后的一个位置,这不是单词边界,因此正则表达式引擎匹配t\B+ 的方式与如果它是t\B,即它只匹配一个t,后跟一个字符(字母、数字、连接符)。

\w 匹配(并且 消耗)单词字符,因此如果您需要匹配(并真正得到结果)t 之后的任何字符直到第一个单词边界,您只需要使用这个\w 模式,t\w*t\w+(如果t 之后必须至少有一个单词字符)。

【讨论】:

  • 根据 ICU 文档 (unicode-org.github.io/icu/userguide/strings/regexp.html) \b 匹配 单词边界,因此 [^\b](除了单词边界之外的任何内容)不应与[^b](除了 ab),应该吗?但是,\b 似乎不能成套使用。但是\B应该做同样的事情(除了单词边界之外的任何东西)。但是为什么`#"t\B+" 不起作用呢?
  • @AndreiHerford 对,[...] 是一个字符集/类。字符类旨在匹配字符\b是一个字边界只在一个字符类之外,因为一个字边界不是一个字符,它是一个匹配某个的零宽度断言位置 在字符串中。所有零宽度断言在字符类中都失去了它们特殊的“零宽度”含义。 [.$] 并不意味着 . 或字符串的结尾,它匹配 .$ char.[.\z] 不匹配 . 或字符串的末尾,它匹配 . 或 @ 987654371@ as \ 被省略,因为\z 不是有效的字符串转义序列。
猜你喜欢
  • 2016-12-06
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 2014-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多