为什么这个regexp不匹配?

为什么这个regexp不匹配?,regex,perl,Regex,Perl,为什么regexp不匹配?我所期望的是: my $genlog_line_1= qr{ \A (?:(\d{6}\s+\d{1,2}:\d\d:\d\d|\d{4}-\d{1,2}-\d{1,2}T\d\d:\d\d:\d\d\.\d+(?:Z|-?\d\d:\d\d)?))? # Timestamp \s+ (?:\s*(\d+)) # Thread ID \s (\w+)

为什么regexp不匹配?我所期望的是:

my $genlog_line_1= qr{
   \A
   (?:(\d{6}\s+\d{1,2}:\d\d:\d\d|\d{4}-\d{1,2}-\d{1,2}T\d\d:\d\d:\d\d\.\d+(?:Z|-?\d\d:\d\d)?))? # Timestamp
   \s+
   (?:\s*(\d+))                     # Thread ID
   \s
   (\w+)                            # Command
   \s+
   (.*)                             # Argument
   \Z
}xs;

my $line = "2018-12-14T17:32:52.236100+08:00        477637459 Query SELECT dv.mandatory,dv.optional FROM dbversion dv";

my ($ts, $thread_id, $cmd, $arg) = $line =~ m/$genlog_line_1/;

print $ts, $thread_id, $cmd, $arg;

正则表达式的主要问题是它没有考虑到
$line
中存在的
+08:00

将其更改为:

Timestamp 2018-12-14T17:32:52.236100
thread_id 477637459 
cmd Query 
arg  SELECT dv.mandatory,dv.optional FROM dbversion dv
演示:


正则表达式的主要问题是它没有考虑到
$line
中存在的
+08:00

将其更改为:

Timestamp 2018-12-14T17:32:52.236100
thread_id 477637459 
cmd Query 
arg  SELECT dv.mandatory,dv.optional FROM dbversion dv
演示:


您的输入中有
+08:00
,但
-?
中的
(?:Z |-?\d\d:\d\d)?
仅说明负值或无符号的值

因此,在第一行正则表达式中,您应该将
-?
替换为
[+-]?
,以匹配可选的
-
+
。此外,由于
+08:00
部分不应属于组1的一部分,我建议使用分支重置组
(?|…|…)
,将组内的不同部分捕获到同一组中,组1:

\A(?:(\d{6}\s+\d{1,2}:\d\d:\d\d|\d{4}-\d{1,2}-\d{1,2}T\d\d:\d\d:\d\d\.\d+(?:Z|-?\d\d:\d\d)?))?(?:\+\d\d:\d\d)?\s+(?:\s*(\d+))\s+(\w+)\s+(.*)\Z
固定模式:

(?|(\d{6}\s+\d{1,2}:\d\d:\d\d)|(\d{4}-\d{1,2}-\d{1,2}T\d\d:\d\d:\d\d\.\d+)(?:Z|[-+]?\d\d:\d\d)?)?
 ^^^                         ^ ^                                         ^     ^^^^         


请注意,如果时间戳始终存在于输入中,则支路重置组后的
可能不必要。

您的输入中有
+08:00
,但
中的
-?
(?:Z |-?\d\d:\d\d)?
仅说明负值或无符号的值

因此,在第一行正则表达式中,您应该将
-?
替换为
[+-]?
,以匹配可选的
-
+
。此外,由于
+08:00
部分不应属于组1的一部分,我建议使用分支重置组
(?|…|…)
,将组内的不同部分捕获到同一组中,组1:

\A(?:(\d{6}\s+\d{1,2}:\d\d:\d\d|\d{4}-\d{1,2}-\d{1,2}T\d\d:\d\d:\d\d\.\d+(?:Z|-?\d\d:\d\d)?))?(?:\+\d\d:\d\d)?\s+(?:\s*(\d+))\s+(\w+)\s+(.*)\Z
固定模式:

(?|(\d{6}\s+\d{1,2}:\d\d:\d\d)|(\d{4}-\d{1,2}-\d{1,2}T\d\d:\d\d:\d\d\.\d+)(?:Z|[-+]?\d\d:\d\d)?)?
 ^^^                         ^ ^                                         ^     ^^^^         


注意:如果时间戳始终存在于输入中,则brach重置组之后的
可能不必要。

查看正则表达式失败位置的一个好方法是使用单步执行匹配过程。在您的例子中,您只需要负的时区偏移量,而不是
+
的时区偏移量。查看正则表达式失败的地方的一个好方法是使用单步执行匹配过程。在您的情况下,您只需要负时区偏移量,而不需要
+
的时区偏移量。分支重置组需要什么版本的Perl?@ysth分支重置组需要什么版本的Perl?@ysth