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

r.r*_*r.r 6 java regex perl

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

"bd".matches("(a)?b(?(1)c|d)")
Run Code Online (Sandbox Code Playgroud)

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

有任何想法吗?谢谢.

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

*date date* date date1*date2
Run Code Online (Sandbox Code Playgroud)

不应该匹配:

*date* date1*date2* *date1*date2 date** ...
Run Code Online (Sandbox Code Playgroud)

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

请不要发布如下答案:

(date*date)|(*date)|(date*)|(date)
Run Code Online (Sandbox Code Playgroud)

tch*_*ist 7

想象一下,如果你能使用一种缺乏else陈述的语言,但你想模仿它.而不是写作

if (condition) { yes part }
else           { no part  }
Run Code Online (Sandbox Code Playgroud)

你必须写

if (condition)   { yes part }
if (!condition)  { no part  }
Run Code Online (Sandbox Code Playgroud)

嗯,这就是你必须要做的,但在模式中.你在没有条件的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
)
Run Code Online (Sandbox Code Playgroud)

你必须在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...
      (?<!  \w)     # if there is no word character to the left
      (?=   \w)     #    then there must be a word character to the right
)
Run Code Online (Sandbox Code Playgroud)

您可能会认识到这是定义\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
)
Run Code Online (Sandbox Code Playgroud)

现在通过重复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...
      (?<!  \w)     # if there is no word character to the left
      (?=   \w)     #    then there must be a word character to the right
)
Run Code Online (Sandbox Code Playgroud)

请注意如何,无论你如何把它们卷,即各自的定义\b\B喜爱的责任完全在的定义\w,从来没有上\W,更别说上\s.

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

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

(?(DEFINE)
    (?<greeklish>            [\p{Greek}\p{Inherited}]   )
    (?<ungreeklish>          [^\p{Greek}\p{Inherited}]  )
    (?<greek_boundary>
        (?(?<=      (?&greeklish))
              (?!   (?&greeklish))
          |   (?=   (?&greeklish))
        )
    )
    (?<greek_nonboundary>
        (?(?<=      (?&greeklish))
              (?=   (?&greeklish))
          |   (?!   (?&greeklish))
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

请注意边界和非边界如何仅使用(&?greeklish),从不(?&ungreeklish)?你永远不需要做任何只做边界的事情.你把没有进入你的lookarounds代替,就像\b\B都这样做.

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

 sub IsGreeklish {
     return <<'END';
 +utf8::IsGreek
 +utf8::IsInherited
 END
 }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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


小智 2

根据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)?|)$可能会起作用。
我假设“日期”是示例中的唯一文本,并且示例中的每组非空格字符都是不同的文本行。

在您传递的文本中,只有一种形式需要伪条件。那就是“日期*日期”。因此,为了清楚起见,我在下面提供了一个 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";
     }
}
Run Code Online (Sandbox Code Playgroud)

输出:

'*date'
matched: '*date'

'date*'
matched: 'date*'

'date'
matched: 'date'

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

'*date*'

'date*date*'

'*date*date'

'date**'
Run Code Online (Sandbox Code Playgroud)