【问题标题】:Regex lookaround construct in Java: advise on optimization neededJava 中的正则表达式环视构造:建议需要优化
【发布时间】:2012-08-02 18:32:58
【问题描述】:

我正在尝试在以下位置的逗号分隔列表中搜索文件名:

text.txt,temp_doc.doc,template.tmpl,empty.zip

我使用 Java 的正则表达式实现。输出要求如下:

  1. 只显示文件名而不是它们各自的扩展名
  2. 排除以“temp_”开头的文件

应该是这样的:

文字

模板

到目前为止,我已经设法编写了或多或少令人满意的正则表达式来处理第一个任务:

[^\\.,]++(?=\\.[^,]*+,?+)

我认为使其符合第二个要求的最佳选择是使用环视构造,但不确定如何编写可靠和优化的表达式。虽然以下正则表达式似乎确实可以满足要求,但如果没有其他原因,它显然是一个有缺陷的解决方案,它依赖于显式的最大文件名长度。

(?!temp_|emp_|mp_|p_|_)(?<!temp_\\w{0,50})[^\\.,]++(?=\\.[^,]*+,?+)

附:我研究正则表达式才几天,所以请不要嘲笑这种新手式的过于复杂的代码:)

【问题讨论】:

  • 您的文件名规则是什么?文件名中允许使用逗号,那么这些会发生吗?在 CSV 文件中,如果用引号括起来,这些都是合法的。
  • 旁注:点在字符类中没有特殊含义。你不能在那里逃脱它。这个[^\\.,] 实际上会禁止点、逗号和退格 - 这将是一个错误。
  • @Tomalak - 请注意还有\\w,这表明它来自Java 字符串。在这种情况下,"[^\\.,]"/[^\.,]/ 相同,因此将忽略反斜杠。我知道,小细节,但至少没有错误:) 仍然 - 好的评论,大多数人都搞错了,一个反斜杠是没用的。
  • @Kobi 你就在这里,但这没什么可依赖的,尤其是在经常切换正则表达式方言时。因为“它恰好可以工作”“无论如何都无所谓” 而草率地转义是许多软件漏洞的原因。始终了解环境的哪个部分需要何种级别的逃逸至关重要。
  • @Tomalak - 我同意!每个人都是赢家!

标签: java regex lookahead negative-lookahead


【解决方案1】:
  • 只显示文件名而不是它们各自的扩展名
  • 排除以“temp_”开头的文件

一种变体是这样的:

(?:^|,)(?!temp_)((?:(?!\.[^.]*(?:,|$)).)+)

这允许

  • 不以“单词字符”开头的文件名(Tim Pietzcker 的解决方案没有)
  • 包含点的文件名(如file.name.ext 将匹配为file.name

但实际上,这真的很复杂。您最好编写一个小函数,在逗号处分割输入并从各部分中去除扩展名。

不管怎样,这里是拆解:

(?:^|,) # 文件名开始:字符串或逗号的开始 (?!temp_) # 否定前瞻:不允许以“temp_”开头的文件名 ( # match group 1 (将包含你的文件名) (?: # 非捕获组(匹配一个允许的字符) (?! # 负前瞻 (不跟在后面): \。 # 一个点 [^.]* # 任意数量的非点(这与扩展名匹配) (?:,|$) # 文件名结束(字符串或逗号结尾) ) # 结束负前瞻 . # 这个字符有效,匹配它 )+ # 结束非捕获组,重复 ) # 结束组 1

http://rubular.com/r/4jeHhsDuJG

【讨论】:

  • 这是一部杰作,虽然需要很长时间才能弄清楚:)
  • @AlexeyDanilov 谢谢。 :) 正如我在回答中指出的那样:尽管许多问题可以通过使用正则表达式来解决,但并非所有问题都应该如此。在这种情况下,完全不使用正则表达式会更聪明。像这样的表达式对于代码维护者来说太复杂了(可能是你,半年后,你忘记了它应该如何工作)。
【解决方案2】:

另一种选择:

(?:temp_[^,.]*|([^,.]*))\.[^,]*

该模式将匹配所有文件名,但捕获仅有效名称。

  • 如果在当前位置模式可以匹配temp_file.ext,它匹配它并且不捕获。
  • 它无法匹配temp_,它会匹配([^,.]*)\.[^,]*,并捕获文件名。

您可以在此处查看示例:http://www.rubular.com/r/QywiDgFxww

【讨论】:

  • 我立刻想到了这样的事情,但是当在循环中调用捕获的组 1 时,输出将是:“text null template empty” - 这将需要另一个步骤来摆脱空值。但总的来说,这是一个不错的简单解决方案。
【解决方案3】:

这个怎么样:

Pattern regex = Pattern.compile(
    "\\b        # Start at word boundary\n" +
    "(?!temp_)  # Exclude words starting with temp_\n" +
    "[^,]+      # Match one or more characters except comma\n" +
    "(?=\\.)    # until the last available dot", 
    Pattern.COMMENTS);

这也允许文件名中包含点。

【讨论】:

  • 这就是我最初打算做的事情,而不是交替使用“temp_”的组合——除了我忘记了你实际上可以使用单词边界来匹配逗号和单词字符。哦,好吧...谢谢你的提示
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-02
  • 2014-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多