【问题标题】:Tokenizing a string with a regular expression使用正则表达式标记字符串
【发布时间】:2016-11-14 09:35:53
【问题描述】:

假设我有一个这样的字符串:abc def ghi jkl(为了简单起见,我在末尾放了一个空格,但这对我来说并不重要)并且我想捕获它的“块”,如下所示:

abc

def

ghi

jkl

当且仅当字符串中有 1-4 个“块”。我已经尝试过以下正则表达式:

^([^ ]+ ){1,4}$

在 Regex101.com,但它只捕获最后一次出现。发出警告:

重复捕获组将仅捕获最后一次迭代。如果您对数据不感兴趣,请在重复组周围放置一个捕获组以捕获所有迭代或使用非捕获组

如何修正正则表达式以达到我的目的?

【问题讨论】:

  • 这是一个 XY 问题。用空格拆分/分解字符串并检查结果数组是否包含 4 个非空元素。但是,可以使用 PCRE 而不是 POSIX 之一来检查和匹配多个后续事件(不是捕获)。
  • 好的,所以我可以仅使用编程语言而不涉及正则表达式来“手动”执行此操作,但有更自动的解决方案吗?事实上,它旨在成为更复杂表达式的一部分。我可以接受 PCRE。
  • 如果您的可执行文件只允许访问捕获组值,则没有适合您的解决方案。
  • 您能解释一下 PCRE 解决方案吗?我在您编辑之前添加了我的评论...

标签: regex tokenize pcre


【解决方案1】:

由于您无法访问代码,您可能使用的唯一解决方案是基于 \G 运算符的正则表达式,它只允许连续匹配和在开始时锚定的前瞻,需要 1 到 4 个非空白字符串中的块。

(?:^(?=\s*\S+(?:\s+\S+){0,3}\s*$)|\G(?!^))\s*\K\S+

regex demo

详情

  • (?:^(?=\s*\S+(?:\s+\S+){0,3}\s*$)|\G(?!^)) - 一个自定义边界,检查是否:

    • ^(?=\s*\S+(?:\s+\S+){0,3}\s*$) - 字符串起始位置 (^),后跟 1 到 4 个非空白块,用 1+ 个空格分隔,也允许尾随/前导空格
    • | - 或
    • \G(?!^) - 上一次成功匹配结束时的当前位置(\G 也匹配字符串的开头,因此我们必须使用负前瞻来排除该匹配位置,因为执行了单独的检查)
  • \s* - 零个或多个空格

  • \K - 一个匹配重置操作符,丢弃所有匹配的文本
  • \S+ - 1 个或多个除空格以外的字符

【讨论】:

  • 不过,表达式有问题。它在 regex101.com 上运行良好,但在 C++ 代码段中使用(使用“普通”C 接口)仅匹配第一个标记,即函数 pcre_exec() 返回 1。例如,对于“abc def ghi”它只会返回“abc”。有什么帮助吗?
  • 这与我的回答无关,但你可以看看this SO thread,我想你会在那里找到解决新问题的方法。
【解决方案2】:

可以在linux上使用tr来完成:

tr -sc 'a-zA-Z' '\n' < text.txt > out_text.txt

在 text.txt 文件中的哪个位置是要规范化的字符串。

【讨论】:

  • 表达式嵌入在常规可执行文件中,所以我不想这样做。
猜你喜欢
  • 2010-11-02
  • 2015-05-13
  • 2012-01-16
  • 1970-01-01
  • 2015-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多