【问题标题】:regex break string into words in dictionary正则表达式将字符串分解为字典中的单词
【发布时间】:2016-11-14 21:06:08
【问题描述】:

我想创建一个正则表达式,以便将字符串分解为字典中的单词。如果字符串匹配,我可以迭代每个组并进行一些更改。有些词是其他词的前缀。但是,像 /(HH|HH12)+/ 这样的正则表达式不会匹配字符串 HH12HH link。正则表达式有什么问题?它应该匹配字符串中的第一个HH12,然后是HH

【问题讨论】:

  • /(HH(?:12)?)+/怎么样
  • @EliSadoff 我必须保留HHHH12,因为在迭代组时我需要知道它是HHHH12。另外,这只是一个例子。想象您只有一本字典,而 HHHH12 在字典中。字典中的单词也在变化。
  • 切换交替,它首先匹配HH,然后就没有其他匹配了。或者在模式末尾添加$
  • @SebastianProske 谢谢。但即使我添加了$,仍然有一组而不是2。link
  • 让我准确地说:您想确保字符串仅由HH12HH 组成,如果是,则标记为HHHH12?还是只想得到连续的HH/HH12

标签: java regex


【解决方案1】:

您想匹配 Java 中应仅包含 HH12HH 子字符串的整个字符串。分两步完成要容易得多:1)检查字符串是否满足要求(此处为matches("(?:HH12|HH)+")),2)提取所有标记(此处为HH12|HHHH(?:12)?,因为第一个替代方案一个未锚定的交替组“获胜”,其余的不被考虑)。

String str = "HH12HH";
Pattern p = Pattern.compile("HH12|HH");
List<String> res = new ArrayList<>();
if (str.matches("(?:HH12|HH)+")) { // If the whole string consists of the defined values
    Matcher m = p.matcher(str);
    while (m.find()) {
        res.add(m.group());
    }
}
System.out.println(res); // => [HH12, HH]

Java demo

另一种方法是正则表达式,它将检查字符串是否满足要求,并在开头进行前瞻,然后将连续标记与 \G 运算符匹配:

String str = "HH12HH";
Pattern p = Pattern.compile("(\\G(?!^)|^(?=(?:HH12|HH)+$))(?:HH12|HH)");
List<String> res = new ArrayList<>();
Matcher m = p.matcher(str);
while (m.find()) {
    res.add(m.group());
}
System.out.println(res);

another Java demo

详情

  • (\\G(?!^)|^(?=(?:HH12|HH)+$)) - 上一个成功匹配的结束 (\\G(?!^)) 或 (|) 字符串的开头 (^),后跟 1+ 个 HH12HH ((?:HH12|HH)+) 序列直到字符串结尾 ($)
  • (?:HH12|HH) - HH12HH

【讨论】:

  • 太棒了!你觉得这个stackoverflow.com/a/16817458/1646996怎么样?它也使用\\G,但看起来并不复杂。
  • 这取决于你需要什么,你没有精确。我在回答中解释了:如果您需要确保字符串 only 包含符合您的模式的标记,则必须首先限定字符串以进行标记化。这就是为什么我提出了一个更复杂的模式,它带有前瞻并将\G 拆分为^(?=...)\G(?!^)\G(?:HH12|HH) 只会匹配字符串开头的多个token,如果字符串后面还有其他文本,匹配的仍然会被收集。
【解决方案2】:

在字符串HH12HH 中,正则表达式(HH|HH12)+ 将以这种方式工作:

HH12HH
^ - both option work, continue
HH12HH
 ^ - First condition is entierly satisfied, mark it as match
HH12HH
  ^ - No Match
HH12HH
   ^ - No Match

当您设置A 标志时,将锚点添加到字符串的开头,其余部分不会引发匹配。如果删除它,该模式将在开头和结尾都匹配 HH

在这种情况下,您有三个选择:

  • 将最长的模式放在首位/(HH12|HH)/AgSee demo我比较喜欢的那个。
  • 相互共享部分并使用可选组/(HH(?:12)?)/AgSee second demo
  • 在末尾加上$,就像/(HH|HH12)$/Ag

【讨论】:

  • 那么如何匹配整个字符串呢?
  • 谢谢!但只有一场小组赛。如果我想要所有组怎么办。例如,第一组应该匹配 HH12 第二组 HH
  • @qqibrow 是什么语言?另请参阅Repeating a Capturing Group vs. Capturing a Repeated Group
  • java.有办法吗?
  • @qqibrow 一个简单的解决方案是使用全局捕获组:((?:HH12|HH)+)
【解决方案3】:

您遇到的问题完全与正则表达式引擎决定匹配什么的方式有关。

正如我所解释的here,有一些正则表达式风格可以选择最长的交替......但你没有使用一个。 Java 的正则表达式引擎是另一种类型:使用第一个匹配替换。

您的正则表达式的工作方式与以下代码非常相似:

if(bool1){
    // This is where `HH` matches
} else if (bool1 && bool2){
    // This is where `HH12` would match, but this code will never execute
}

解决此问题的最佳方法是将单词倒序排列,以便 HH12 出现在 HH 之前。

那么,你可以只匹配一个改动:

HH12|HH

什么匹配应该很明显,因为你可以得到每个匹配的结果。

(您也可以将每个单词放在自己的捕获组中,但这有点难处理。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多