Awk 是否有一个字段存储正则表达式中使用的确切字段分隔符FS,相当于RS的RT?

Awk 是否有一个字段存储正则表达式中使用的确切字段分隔符FS,相当于RS的RT?,awk,gnu,Awk,Gnu,在这方面,我们可以阅读: 当RS是单个字符时,RT包含相同的单个字符。但是,当RS是正则表达式时,RT包含与正则表达式匹配的实际输入文本 此变量RT在中非常有用 类似地,我们可以将正则表达式设置为字段分隔符。例如,在这里我们允许它是“;”或“|”: $gawk-F';“”{print NF}' 是否有办法使用用于拆分每个字段的特定字段分隔符“重新打包”字段 使用gnu awk,使用提供的正则表达式为匹配的分隔符提供额外的第四个参数: s=“你好;你好吗” awk'split($0,flds,/[

在这方面,我们可以阅读:

RS
是单个字符时,
RT
包含相同的单个字符。但是,当
RS
是正则表达式时,
RT
包含与正则表达式匹配的实际输入文本

此变量
RT
在中非常有用

类似地,我们可以将正则表达式设置为字段分隔符。例如,在这里我们允许它是“;”或“|”:

$gawk-F';“”{print NF}'
是否有办法使用用于拆分每个字段的特定字段分隔符“重新打包”字段

使用
gnu awk
,使用提供的正则表达式为匹配的分隔符提供额外的第四个参数:

s=“你好;你好吗”

awk'split($0,flds,/[| |]/,seps){for(i=1;seps中的i;i++)printf“%s%s”,flds[i],seps[i];print flds[i]}'split的另一种选择是使用match查找字段分隔符并将其读入数组:

awk-F'[|]'{
str=$0;#将str设置为行
while(match(str,FS)){#通过字段分隔符的rach匹配进行循环
map[cnt+=1]=substr(str,RSTART,RLENGTH);#创建一个字段分隔符数组
str=substr(str,RSTART+RLENGTH)#将str设置为匹配字符串后的字符串其余部分
}
对于(i=1;iAs,gawk有
split()
(和
patsplit()
,即
FPAT
,正如
split()
FS
-参见)来做你想做的事情。如果你想用POSIX awk实现同样的功能,那么:

$ cat tst.awk
function getFldsSeps(str,flds,fs,seps,  nf) {
    delete flds
    delete seps
    str = $0

    if ( fs == " " ) {
        fs = "[[:space:]]+"
        if ( match(str,"^"fs) ) {
            seps[0] = substr(str,RSTART,RLENGTH)
            str = substr(str,RSTART+RLENGTH)
        }
    }

    while ( match(str,fs) ) {
        flds[++nf] = substr(str,1,RSTART-1)
        seps[nf]   = substr(str,RSTART,RLENGTH)
        str = substr(str,RSTART+RLENGTH)
    }

    if ( str != "" ) {
        flds[++nf] = str
    }

    return nf
}

{
    print
    nf = getFldsSeps($0,flds,FS,seps)
    for (i=0; i<=nf; i++) {
        printf "{%d:[%s]<%s>}%s", i, flds[i], seps[i], (i<nf ? "" : ORS)
    }
}
我们将得到以下输出,其中每个字段显示为字段编号,然后是
[…]
中的字段值,然后是
中的分隔符,所有这些都在
{…}
中(请注意,如果FS是
且记录以空格开头,则填充
seps[0]
):

$awk-F'[,|]'-F tst.awk文件1
你好,你好吗
{0:[]}{1:[你好;你好]}{2:[你好]}
$awk-f tst.awk文件2
你好,你好吗
{0:[]}{1:[你好]<>}{2:[你好]<>}{3:[你是吗]}
$awk-f tst.awk文件3
你好,你好吗
{0:[]<>}{1:[你好]<>}{2:[你好]<>}{3:[你是吗]}

jfyi这是应用同一个正则表达式两次。一次用于字段拆分,第二次用于捕获分隔符。如果拆分正则表达式很复杂,那么它会减慢速度。您可能需要更改(或讨论)的另一件事是循环范围-使用defaullt FS时,
seps
数组可以从0开始,因为seps[0]然后保存flds[1]之前出现的空白,通常在字段拆分过程中会被丢弃。这里可能值得一提的是,您不能将常量regexp传递给用户定义的函数,因此,当您可以执行
split($0,arr,/re/)
时,您不能编写自己的函数
foo()
和do
foo($0,arr,/re/)
,您必须将其称为
foo($0,arr,“re”)
而不是使用动态regexp,因为
/re/
在该上下文中意味着
($0~/re/?1:0)
。GNU awk有一个称为强类型regexp的增强功能,它通过在常量regexp前面加上
@
前缀来解决该问题,例如
foo($0,arr,@/re/)
-看到了,很高兴知道。我从来都不知道
@/re/
@fedorqui'sostoppharming',它们被允许作为
split()
的参数,你只是忘了引用你用来初始化awk变量的字符串,试试
gawk-v patt='@/“{print split($0,a,patt)}“哦,你说得对,@EdMorton!事实上,现在我注意到我对文档的理解是另一种方式:它在split和others中可以使用(强类型regexp常量不能像常规regexp常量那样在任何地方都使用,因为这会使语言更加混乱。相反,你只能在某些上下文中使用它们)
$ head file{1..3}
==> file1 <==
hello;how|are you

==> file2 <==
hello how are_you

==> file3 <==
    hello how are_you
$ awk -F'[,|]' -f tst.awk file1
hello;how|are you
{0:[]<>}{1:[hello;how]<|>}{2:[are you]<>}

$ awk -f tst.awk file2
hello how are_you
{0:[]<>}{1:[hello]< >}{2:[how]< >}{3:[are_you]<>}

$ awk -f tst.awk file3
    hello how are_you
{0:[]<    >}{1:[hello]< >}{2:[how]< >}{3:[are_you]<>}