正则表达式在 C# 中匹配,但在 java 中不匹配
Posted
技术标签:
【中文标题】正则表达式在 C# 中匹配,但在 java 中不匹配【英文标题】:Regex matches in C# but not in java 【发布时间】:2012-01-11 19:54:39 【问题描述】:我有以下正则表达式(很长,我知道):
(?-mix:((?-mix:(?-mix:\\%).*?(?-mix:\%\)|(?-mix:\\).*?(?-mix:\\?))
|(?-mix:\\|\\%)))
我用来分割字符串的。它在 C# 中正确匹配,但是当我将代码移至 Java 时,它不匹配。此正则表达式是否有任何仅 C# 的特殊功能?
源码生成为:
String source = Pattern.quote("% assign foo = values %. foo[0] .");
在 C# 中是:
string source = @"% assign foo = values %. foo[0] .";
C#版本是这样的:
string[] split = Regex.split(source, regex);
在 Java 中我都试过了:
String[] split = source.split(regex);
还有
Pattern p = Pattern.compile(regex);
String[] split = p.split(source);
【问题讨论】:
可能是不正确的字符串转义?! 你能给出一个你的表达式应该匹配的字符串吗? 里面没有明显的损坏。问题可能出在使用它的 Java 代码上吗?例如,当find
是需要时,习惯于使用其他语言的正则表达式的人通常会在Java 中使用matches
。如果您发布代码-sn-p,它可能会有所帮助。 (顺便说一句,你为什么使用这么多(?-mix:...)
的实例?你没有使用^
、$
、字母、空格或#
,即使你是,你也只需要整个正则表达式的一个实例。)
好吧,你的 Java sn-ps 看起来也不错。唔 。 . . source
是什么样的?而且,我假设您发布的正则表达式是您从 System.out.println(regex);
(或等效)获得的?
你应该看看你是否可以通过一次剥离一点点来将问题缩小到正则表达式的一部分。您还应该确认您正在搜索的字符串在两种语言中确实是相同的(例如,没有一些字符集搞砸之类的)。
【参考方案1】:
这是一个包含您的代码的示例程序:http://ideone.com/hk3uy
Java 和其他语言之间有一个主要区别:Java 不会将捕获的组作为标记添加到结果数组中 (example)。这意味着所有分隔符都将从结果中删除,尽管它们将包含在 .Net 中。
我知道的唯一选择是不使用split
,而是获取匹配列表并手动拆分。
【讨论】:
+1 我没有意识到 .Net 包含捕获的组,但您是对的:“如果在 Regex.Split 表达式中使用捕获括号,则任何捕获的文本都包含在结果字符串中数组”(msdn.microsoft.com/en-us/library/8yttk7sy.aspx)。但这不是“Java”与“其他语言”; Java 的方法在我的经验中更为常见,尽管 .Net 也不是唯一的。 (Python 像 .Net 一样。) 确实,这似乎是问题所在。 @ruakh - 这很公平。我不会处理太多语言,但通常会包含分隔符,或者至少可以选择包含(例如在 php 的PREG_SPLIT_DELIM_CAPTURE
标志中)。
顺便说一下,在许多情况下,.Net-split-pattern-with-capture-groups 可以转换为 Java-split-pattern-with-zero-width-lookahead-and-look - 背后的断言。例如,C# 的 Regex.Split("123-456", "(-)")
等价于 Java 的 Pattern.compile("(?=-)|(?<=-)").split("123-456")
。但在这种情况下,我认为将如此复杂的拆分模式塞进一个零宽度的lookbehind assertion 中是不可行的。 . .
@ruakh - 这是一个很好的观点。实际上,我并没有过多关注实际模式(它看起来太自动生成了,而且我已经看到你已经给出了更好的选择,所以我只是对此进行了投票) - 但你是对的。通常可以通过多种方式实现相同的结果。【参考方案2】:
我认为问题在于您如何定义source
。在我的系统上,这是:
String source = Pattern.quote("% assign foo = values %. foo[0] .");
等价于:
String source = "\\Q% assign foo = values %. foo[0] .\\E";
(也就是说,它添加了一个杂散的\Q
和\E
),但是方法的定义方式,你的Java 实现可以把它等同于这个:
String source = "\\% assign foo = values %\\\\.\\\\ foo\\[0\\] \\\\\\.";
(即插入大量反斜杠)。
您的正则表达式本身似乎很好。这个程序:
public static void main(final String... args)
final Pattern p = Pattern.compile("(?-mix:((?-mix:(?-mix:\\\\%).*?(?-mix:\\%\\)|(?-mix:\\\\).*?(?-mix:\\\\?))|(?-mix:\\\\|\\\\%)))");
for(final String s : p.split("a%b%cde%f%ghij%k"))
System.out.println(s);
打印
a
c
e
g
i
j
k
也就是说,它成功地将 %b%
、d
、%f%
、h
、 和
%
视为分割点,并具有您所期望的所有非贪婪。但是根据记录,如果我将p
剥离到只是,它也可以工作
Pattern.compile("\\%.*?%\\|\\\\.*?\\\\?|\\\\|\\%");
;-)
【讨论】:
是的,该行是人为添加的。 :) 感谢您的帮助,问题实际上是java在拆分结果中不包含分隔符。【参考方案3】:使用\\
代替\
以及其他符号
【讨论】:
其实这不是硬编码的字符串,而是 String.format() 操作的产物。它已经逃脱了。以上是关于正则表达式在 C# 中匹配,但在 java 中不匹配的主要内容,如果未能解决你的问题,请参考以下文章