除了“#”之后,正则表达式抓住“WORD”

时间:2016-04-15 19:54:42

标签: regex regex-lookarounds

我在这里看到一个SO问题,它使用Java MatcherPattern来尝试突出显示文本,类似于Regex101突出显示的方式。他的规范是在JTextArea中突出显示任何前面没有文字字符“#”的文字字符串。我打算建议创建你自己的Matcher,然后OP删除了他的问题:(

那是背景,现在这是我的问题。我如何使用正则表达式来获取文字字符串,除非它在一行中的特定字符串/字符之后(但不是必须相邻)?

示例,如果我想从以下

中选择字符串“tester”
  

tester,#thetes

     

测试测试员#测试测试员

     

测试

我希望我的正则表达式会选择

  

测试人员,#testter

     

测试测试人员 #test tester

     

测试

但不是最后一位“测试员”。

使用Regex101,我得到的最接近的是/(?=tester)(?<!#)tester/g,但这会选择最后一个“测试者”字符串,因为我无法做“动态”?据我所知,(非零)长度回顾。

编辑:

我的问题不是Java特定的,否则我会放置Java标记。除非Regex101错误,否则我不能使用Limiting Repetition,因为“Lookbehinds需要为零宽度,因此不允许使用量词”。

我在Java中测试了WiktorStribiżew正则表达式,它运行正常。看到它是一个评论,而不是一个答案,我所能做的就是+1,Java String是(?<!#.{0,1000})\\btester\\b。我根据以下Java字符串tester, #tester\ntest tester # test testern\tester

测试了它

附带问题,还没有完全定义的方法来处理所有语言的正则表达式?或者Regex101只是一个糟糕的测试工具(我使用的是默认的PHP引擎)?

我将来会考虑使用RegexStormRegexHero

3 个答案:

答案 0 :(得分:1)

在Java中,如果预期子字符串之前的字符数不是无限的,您可以利用约束宽度的lookbehind 。这意味着你可以在lookbehind中使用限制量词。 (有一个允许在Java 8中使用*的错误,但是利用它不是一个好主意,因为在其他版本中可能会修复错误。)请注意,限制量词内部的值越大,性能越高可能会下降。

所以,你可以使用

String rx = "(?<!#.{0,1000})\\btester\\b";

请参阅IDEONE demo

该模式匹配任何整个单词tester(因为\b是一个单词边界),前面没有#,后跟0到1000任何字符,但是换行符(带{ {1}},它也会匹配换行符。

在线测试中的注意事项:因为regex101不支持具有约束宽度外观的正则表达式(如Java或ICU)。使用基于.NET的在线测试人员,例如RegexStormRegexHero。或者只使用最好的Java正则表达式在线测试人员:RegexPlanetocpsoft

<小时/> 现在, 谈论通用解决方案 Match what you do not need, and match and capture what you need to keep.

这是the pattern

DOTALL

请注意,绿色突出显示的#.*\btester\b|\b(tester)\b 是驻留在捕获组#1中的那些,而组0中的那些是regex101中的蓝色。您可以检查这些子值属于哪个组,并在代码中采取适当的操作。

在Java中,要检查组是否匹配,只需使用

tester

答案 1 :(得分:0)

您可以使用以tester开头的#之前的可选组。然后检查是否存在第一组并相应更换。

String text = "tester, #tester\ntester foo\ntest tester # test tester\ntester";
Pattern p = Pattern.compile( "(#[^#\n]*)?(\\btester\\b)" );
Matcher m = p.matcher( text );

StringBuffer sb = new StringBuffer();
while(m.find()) {
    if (m.group(1) == null)
        m.appendReplacement(sb, "<em>" + m.group(2) + "</em>");
    else
        m.appendReplacement(sb, m.group());
}
m.appendTail(sb);
System.err.println(sb);

<强>输出:

<em>tester</em>, #tester
<em>tester</em> foo
test <em>tester</em> # test tester
<em>tester</em>

答案 2 :(得分:0)

虽然我最初认为这更像是在Java中突出显示匹配,但我发现here这段代码可以解决您的所有问题。略有改动以符合您的示例:

  JTextArea textArea = new JTextArea(10, 30);

  String text = "test tester # test tester";

  textArea.setText(text);

  Highlighter highlighter = textArea.getHighlighter();
  HighlightPainter painter = 
         new DefaultHighlighter.DefaultHighlightPainter(Color.pink);
  int p0 = text.indexOf("tester");
  int p1 = p0 + "tester".length();
  highlighter.addHighlight(p0, p1, painter );

  JOptionPane.showMessageDialog(null, new JScrollPane(textArea));

如果您仅在p0==0text.charAt(p0-1) != '#'时应用突出显示,则您不需要正则表达式。 (或者p0 < text.indexOf("#")时,我不确定你想要什么。)