java支持if-then-else regexp构造(Perl构造)吗?

尝试编译以下正则表达式时,我收到PatternSyntaxException:

"bd".matches("(a)?b(?(1)c|d)") 

这个正则表达式匹配bd和abc。 它与bc不匹配。

有任何想法吗? 谢谢。

好吧,我需要写正则表达式来匹配接下来的4个字符串:

 *date date* date date1*date2 

不应该匹配:

 *date* date1*date2* *date1*date2 date** ... 

但这应该通过单一匹配来完成,而不是几个。

请不要发布以下答案:

 (date*date)|(*date)|(date*)|(date) 

根据OP的编辑和样本添加新答案:

ok i need to write regex to match next 4 strings:
*date date* date date1*date2
should not match:
*date* date1*date2* *date1*date2 date** ...

如果我认为我理解你,你可以使用基于Alan Moore伪条件技巧的正则表达式。

像这样的东西^(?:[*]())?date(?:(?!\1)[*](?:date)?|)$可能有效。
我认为’date’是样本中唯一的文本,样本中的每组非空格字符都是不同的文本行。

在您传递的文本中,只有一个表单需要伪条件。 那是’日期*日期’。 所以,我在下面包含了一个Perl示例(因为我没有Java编译器),为了清晰起见扩展了正则表达式。

 use strict; use warnings; my @samps = qw( *date date* date date*date *date* date*date* *date*date date** ); for my $str (@samps) { print "\n'$str'\n"; if ($str =~ / ^ # Begin of string (?: # Expr grouping [*]() # Asterisk found then DEFINE capture group 1 as empty string )? # End expr group, optional, if asterisk NOT found, capture group 1 stays UNDEFined date # 'data' (?: # Expr grouping (?!\1) # Pseudo conditional: If no asterisk (group 1 is UNDEF), then [*](?:date)? # look for '*' folowed by optional 'data' | # OR, ) # Asterisk or not, should be nothing here $ # End of string /x) { print "matched: '$str'\n"; } } 

输出:

 '*date' matched: '*date' 'date*' matched: 'date*' 'date' matched: 'date' 'date*date' matched: 'date*date' '*date*' 'date*date*' '*date*date' 'date**' 

想象一下,如果你能使用一种缺少else语句的语言,但你想模仿它。 而不是写作

 if (condition) { yes part } else { no part } 

你必须写

 if (condition) { yes part } if (!condition) { no part } 

嗯,这就是你必须要做的,但在模式中。 你在没有条件的Java中做的是你在ELSE块中重复这个条件,但是否定它,它实际上是一个OR块。

因此,例如,而不是像Perl这样的语言在模式中使用条件支持来编写它:

 # definition of \b using a conditional in the pattern like Perl # (?(?<= \w) # if there is a word character to the left (?! \w) # then there must be no word character to the right | (?= \w) # else there must be a word character to the right ) 

你必须在Java中写道:

 # definition of \b using a duplicated condition like Java # (?: (?<= \w) # if there is a word character to the left (?! \w) # then there must be no word character to the right | # ...otherwise... (? 

你可能会认识到它是\b的定义。 然后类似于\B的定义,首先使用条件:

 # definition of \B using a conditional in the pattern like Perl # (?(?<= \w) # if there is a word character to the left (?= \w) # then there must be a word character to the right | (?! \w) # else there must be no word character to the right ) 

现在通过重复OR分支中的(现在否定的)条件:

 # definition of \B using a duplicated condition like Java # (?: (?<= \w) # if there is a word character to the left (?! \w) # then there must be no word character to the right | # ...otherwise... (? 

请注意你如何滚动它们并不重要, \b\B的相应定义仅仅依赖于\w的定义,永远不会在\W ,更不用说在\s

能够使用条件不仅可以节省打字,还可以减少错误的机会。 它们也可能是您不关心两次评估病情的情况。

在这里,我利用它来定义几个正则表达式子程序,它们为我提供了一个希腊语primefaces和相同的边界:

 (?(DEFINE) (? [\p{Greek}\p{Inherited}] ) (? [^\p{Greek}\p{Inherited}] ) (? (?(?<= (?&greeklish)) (?! (?&greeklish)) | (?= (?&greeklish)) ) ) (? (?(?<= (?&greeklish)) (?= (?&greeklish)) | (?! (?&greeklish)) ) ) ) 

注意边界和非边界只使用(&?greeklish) ,从不(?&ungreeklish) ? 你永远不需要做任何只做边界的事情。 你把not放入你的外观中,就像\b\B一样。

虽然在Perl中,定义一个新的自定义属性可能更容易(尽管不那么通用), \p{IsGreeklish} (因此它的补充\P{IsGreeklish} ):

  sub IsGreeklish { return <<'END'; +utf8::IsGreek +utf8::IsInherited END } 

虽然不是因为Java缺乏对条件语的支持,而是因为它的模式语言不允许(DEFINE)块或正则表达式子程序调用,所以你将无法将其中的任何一个转换为Java; (?&greeklish) - 事实上,你的模式甚至无法在Java中进行递归。 你也不能在Java中定义像\p{IsGreeklish}这样的自定义属性。

当然,Perl正则表达式中的条件可能不仅仅是外观:它们甚至可以是代码块来执行 - 这就是为什么你当然不希望被迫两次评估相同的条件,以免它产生副作用。 这不适用于Java,因为它无法做到这一点。 你不能混合使用模式和代码,这会限制你比你习惯这样做之前想象的更多。

你可以用Perl正则表达式引擎做很多事情,你可以用别的语言来做,这只是其中的一部分。 毫无疑问,新编程Perl的第4版中大大扩展的Regexes章节,加上完全重写的Unicode章节,现在紧跟Regexes章节(已被提升为内核的一部分),具有组合页数类似130页的东西,所以从第3版开始,模式匹配的旧章节的长度增加了一倍。

你刚才看到的是新版第4版的一部分,应该会在下个月左右出版。

Java不支持条件,但有一个技巧可以在它的位置使用。 一探究竟:

 String[] test = { "abc", "abd", "bc", "bd", "ad", "ac" }; for (String s : test) { System.out.printf("%-4s: %b%n", s, s.matches("(?:a())?b(\\1c|(?!\\1)d)")); } 

输出:

 abc : true abd : false bc : false bd : true ad : false ac : false 

如果字符串不以a开头,则第一个捕获组不参与匹配,反向引用\1失败,就像条件组中的(1)一样。 否则它匹配一个空字符串,与该组相同。

条件的另一个方面是它执行或; 如果条件为真,则第二个分支不应该成功(因此abd不应该匹配)。 第二个分支中的否定反向引用实现了这一点。

这个技巧适用于几乎所有流行的Perl派生的风格,包括Java,.NET,Python,PHP(PCRE)和Ruby(Oniguruma)。 它在像JavaScript和ActionScript这样的ECMAScript实现中不起作用。


编辑:好的,你已经添加了一些示例字符串,并且@sln已经展示了如何将它们与伪条件匹配,但我想知道你是否真的需要它们。 您的“有效”字符串似乎至少包含一个date ,其间穿插着最多一个* ,可以表示为

 ^\*date|date(?:\*(?:date)?)?$ 

这是一个包含@ sln的正则表达式以及我的正则演示的演示

没有这个设施,你不可能继续。 我希望你不会陷入试图将多种function集成到单个正则表达式中的常见陷阱?

请描述一下你的问题。 我确信有一个比使用外部库来实现您设计的解决方案更好的选择。

阅读Java 1.5 Pattern规范 , Java 1.6 Pattern规范和Java 7规范它似乎没有if-then-else结构。

可以在此博客文章中找到问题中正则表达式的解释和(不支持条件的其他语言的一些不同选项)。 可以在此页面阅读完整说明(并进一步确认Java不支持)

您可能会寻找第三方库来进行模式匹配,但它不会与String类集成。

根据这里的维基百科文章,在引擎比较表中,java的doesen不做条件。