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不做条件。