在AWK(或GAWK)中,如何确定第n个单词的起始位置?

在AWK(或GAWK)中,如何确定第n个单词的起始位置?,awk,gawk,Awk,Gawk,示例:n=3,输入为 foo bar baz a b c d e f g h 12 34 5 678 输出应为: 13 5 8 最简单的可能是: $ awk -v n=3 '{print index($0,$n)}' file 13 5 8 但它很容易出错,需要进行一些检查$n是第三个单词(或由FS字段分隔符分隔的字段)索引返回该事件开始的位置(以字符为单位)。如果FS是默认值(空格,然后是一些空格),您可能希望从空格开始,然后在位置上添加一个空格: $ awk -v n=3 '

示例:n=3,输入为

foo  bar    baz
a b c d e f g h
12  34 5 678
输出应为:

13
5
8

最简单的可能是:

$ awk -v n=3 '{print index($0,$n)}' file
13
5
8
但它很容易出错,需要进行一些检查
$n
是第三个单词(或由
FS
字段分隔符分隔的字段)<代码>索引返回该事件开始的位置(以字符为单位)。如果
FS
是默认值(空格,然后是一些空格),您可能希望从空格开始,然后在位置上添加一个空格:

$ awk -v n=3 '{print 1 + index($0," " $n)}' file
13
5
8
。。。正如注释中所指出的,如果第n个单词与前一个单词的开头匹配,则也容易出现错误

我们可以使用GNU awk的
split
的seps功能:

$awk-vn=3'{
s=1#将s重置为1
拆分($0,a,/+/,b)#拆分为a,分隔符拆分为b

对于(i=1;i您可以使用
match
执行此操作:

$ awk 'match($0, /[[:blank:]]*([^[:blank:]]+[[:blank:]]+){2}/) {
    print RLENGTH + 1 
}' file
13
5
8
或者将参数与动态正则表达式一起使用:

$ awk -v n=3 'match($0, "[[:blank:]]*([^[:blank:]]+[[:blank:]]+){" n - 1 "}") { 
    print RLENGTH + 1 
}' file
13
5
8
这将搜索可选的前导空格(空格或制表符),后跟非空格,后跟空格,
n-1
次,其中
n
是字号。
match
设置变量
RSTART
RLENGTH
(在本例中,
RSTART==1
).
RLENGTH
给出匹配的长度,因此后面的一个字符是第n个单词的起始位置

既然您提到了GNU awk,您可以通过使用
\s
(实际上是
[:space:]
,但在这里也适用)和非空格
\s
,来缩短时间:

$ awk -v n=3 'match($0, "\\s*(\\S+\\s+){" n - 1 "}") { print RLENGTH + 1 }' file

在动态正则表达式中,反斜杠本身需要转义。

这将适用于任何字段分隔符,包括多字符regexp,使用GNU awk作为要拆分的第四个参数()

请注意,由于我们使用
FS
作为
split()
的参数,它将被视为动态regexp(即存储在字符串中的regexp),因此
FS
中的任何反斜杠都需要加倍


还要注意,我们从0开始计数循环,而不是从1开始,因为对于默认FS,flds[1](即$1)之前的任何前导空格都存储在seps[0]中。flds[0]将始终为空,对于非默认FS seps[0]也将是空的,不会造成任何伤害,包括在所有情况下的长度。

唉,这太容易出错,例如,
$2==$n
@user31264肯定是。这只是一个开始。:DThank you,dynamic regex的想法很好。当使用默认FS和使用单个字符的FS时,这绝对是正确的方法
[:blank://code>更改为
X
,并删除前导的
X*
,这将是一个调整。不过,当使用多字符regexp的FS时,它会变得更有趣:-)!
$ awk -v n=3 'match($0, "\\s*(\\S+\\s+){" n - 1 "}") { print RLENGTH + 1 }' file
$ cat tst.awk
{    
    split($0,flds,FS,seps)
    indent = 1
    for (i=0; i<n; i++) {
        indent += length(flds[i] seps[i])
    }
    print indent
}

$ awk -v n=3 -f tst.awk file
13
5
8
$ cat file2
foo.+.bar.-.baz
a.+.b.-.c.+.d.-.e.+.f.-.g.+.h
12.-.34.+.5.-.678

$ awk -F'[.][+-][.]' -v n=3 -f tst.awk file2
13
9
11