如果我有一个awk命令

pattern { ... }

和模式使用捕获组,我怎么能访问字符串,所以在块捕获?


当前回答

注意:gensub的使用不是POSIX兼容的

您也可以在vanilla awk中模拟捕获,不需要扩展。这并不直观:

步骤1。使用gensub将匹配的字符串与一些不出现在字符串中的字符包围起来。 步骤2。对角色使用分裂。 步骤3。拆分数组中的其他每个元素都是捕获组。

$ echo 'ab cb ad' | awk '{ split(gensub(/a./,SUBSEP"&"SUBSEP,"g",$0),cap,SUBSEP); print cap[2]"|" cap[4] ; }'
ab|ad

其他回答

注意:gensub的使用不是POSIX兼容的

您也可以在vanilla awk中模拟捕获,不需要扩展。这并不直观:

步骤1。使用gensub将匹配的字符串与一些不出现在字符串中的字符包围起来。 步骤2。对角色使用分裂。 步骤3。拆分数组中的其他每个元素都是捕获组。

$ echo 'ab cb ad' | awk '{ split(gensub(/a./,SUBSEP"&"SUBSEP,"g",$0),cap,SUBSEP); print cap[2]"|" cap[4] ; }'
ab|ad

我认为gawk match()-to-array仅用于捕获组的第一个实例。

如果您想要捕获多个东西,并对它们执行任何复杂的操作,那么可能

gawk 'BEGIN { S = SUBSEP 
          } { 
              nx=split(gensub(/(..(..)..(..))/, 
                              "\\1"(S)"\\2"(S)"\\3", "g", str), 
                       arr, S)
              for(x in nx) { perform-ops-over arr[x] } }'

这样就不受gensub()或match()的约束,gensub()限制了修改的复杂性。

通过纯粹的试错,我注意到在unicode模式下gawk的一个警告:对于一个有效的unicode字符串뀇꿬,包含下面列出的6个八进制代码:

场景1:匹配单个字节很好,但也会向您报告多字节的RSTART为1,而不是字节级的答案为2。它也不会提供关于\207是第一个延续字节还是第二个延续字节的信息,因为RLENGTH在这里总是1。

$ gawk 'BEGIN{ print match("\353\200\207\352\277\254", "\207") }' 
$ 1 

场景2:Match也适用于这样的unicode无效模式

$ gawk 'BEGIN{ match("\353\200\207\352\277\254", "\207\352"); 
$                print RSTART, RLENGTH }' 
$ 1 2

场景3:您可以针对unicode非法字符串检查模式的存在(\300 \xC0对于所有可能的字节对都是UTF8-invalid)

$ gawk 'BEGIN{ print ("\300\353\200\207\352\277\254" ~ /\200/) }' 
$ 1

场景4/5/6:错误消息将显示(a) match()与unicode-invalid字符串,index()为任何一个参数为unicode-invalid/incomplete。

$ gawk 'BEGIN{ match("\300\353\200\207\352\277\254", "\207\352"); print RSTART, RLENGTH }' gawk: cmd. line:1: warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale. 2 2

$ gawk 'BEGIN{ print index("\353\200\207\352\277\254", "\352") }' gawk: cmd. line:1: warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale. 0

$ gawk 'BEGIN{ print index("\353\200\207\352\277\254", "\200") }' gawk: cmd. line:1: warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale. 0

在gawk中,您可以使用match函数来捕获括号中的组。

gawk 'match($0, pattern, ary) {print ary[1]}' 

例子:

echo "abcdef" | gawk 'match($0, /b(.*)e/, a) {print a[1]}' 

输出的cd。

注意gawk的具体用法,它实现了所讨论的特性。

对于可移植的替代方案,您可以使用match()和substr实现类似的结果。

例子:

echo "abcdef" | awk 'match($0, /b[^e]*/) {print substr($0, RSTART+1, RLENGTH-1)}'

输出的cd。

这是我一直需要的东西,所以我为它创建了一个bash函数。这是基于格伦·杰克曼的答案。

定义

将此添加到您的.bash_profile等。

function regex { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'0'}']}'; }

使用

捕获文件中每一行的正则表达式

$ cat filename | regex '.*'

为文件中的每一行捕获第一个正则表达式捕获组

$ cat filename | regex '(.*)' 1

你可以使用GNU awk:

$ cat hta
RewriteCond %{HTTP_HOST} !^www\.mysite\.net$
RewriteRule (.*) http://www.mysite.net/$1 [R=301,L]

$ gawk 'match($0, /.*(http.*?)\$/, m) { print m[1]; }' < hta
http://www.mysite.net/