可选组从不匹配

Evg*_*sky 2 sed regular-expression

以下是我正在努力解决的问题的简化版本。我有这个文件:

1 H 200 OK.Content-Length: 2422 x
2 H 403 Forbidden.z
Run Code Online (Sandbox Code Playgroud)

我尝试让 sed 匹配 HTTP 状态和 - 如果存在 - 内容长度,如下所示:

> sed -nEe 's,^.*H ([ 0-9a-zA-Z]+).*(Content-Length: ([0-9]+))?.*$,\1 \3,p' x
200 OK 
403 Forbidden 
Run Code Online (Sandbox Code Playgroud)

所以可选组永远不会匹配。如果我通过删除问号将其设为非可选,它确实会匹配内容长度,但不会匹配没有问号的行:

> sed -nEe 's,^.*H ([ 0-9a-zA-Z]+).*(Content-Length: ([0-9]+)).*$,\1 \3,p' x
200 OK 2422
Run Code Online (Sandbox Code Playgroud)

我怎样才能让 sed 给出以下输出?

200 OK 2422 
403 Forbidden 
Run Code Online (Sandbox Code Playgroud)

NB 我也尝试了perl,它支持惰性匹配(.*?),但没有成功:

> perl -pe 's,^.*H ([ 0-9a-zA-Z]+).*?(Content-Length: ([0-9]+))?.*?$,\1 \3,' x
200 OK 
403 Forbidden 
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 5

由于该(Content....)组是可选的,因此在贪婪版本中,反对:

1 H 200 OK.Content-Length: 2422 x
Run Code Online (Sandbox Code Playgroud)

^.*H ([ 0-9a-zA-Z]+)matches 1 H (200 OK),然后.*匹配到末尾,并且(Content-Length: ([0-9]+))?next.*都匹配行末尾的空字符串。

在非贪婪版本中,第一个.*?尝试尽可能少地匹配,但这没什么,因为该行的其余部分 ( .Content-Length: 2422 x) 确实匹配(Content-Length: ([0-9]+))?,后面的所有内容都没有,.*?$直到该行末尾。

您需要确保第 .*一次捕获后的第一个不会滚动 a Content-Length: \d+,例如在每个步骤中使用一些负面的前瞻:

perl -lne 'print if
 s/^.*?H ([\s\w]+)(?:(?!Content-Length: \d+).)*(?:Content-Length: (\d+))?.*$/\1\2/'
Run Code Online (Sandbox Code Playgroud)

虽然你可以简单地这样做:

perl -lne '
  if (/H\s+([\s\w]+)(.*)/) {
    my $status = $1;
    print "$status" . ($2 =~ /Content-Length: (\d+)/ && " $1");
  }'
Run Code Online (Sandbox Code Playgroud)

或者:

sed -nE 's/^.*H[[:space:]]+([[:space:][:alnum:]]+).*Content-Length: ([[:digit:]]+).*$/\1 \2/p;t
         s/^.*H[[:space:]]+([[:space:][:alnum:]]+).*$/\1/p'
Run Code Online (Sandbox Code Playgroud)

也就是说,不要尝试通过一次替换来完成它。