gpt4 book ai didi

awk - 使用 Gnu AWK 检索匹配的正则表达式记录分隔符

转载 作者:行者123 更新时间:2023-12-05 08:54:01 25 4
gpt4 key购买 nike

我使用 AWK 处理一个文本文件,将其拆分为多个记录。作为记录分隔符 RS 我使用正则表达式。有没有办法获取找到的记录分隔符,因为 RS 只代表正则表达式字符串?

示例:

BEGIN { RS="a[0-9]*. "; ORS="\n-----\n"}
/foo/ {print $0 RS;}
END {}

输入文件:

a1. Hello
this
is foo
a2. hello
this
is bar
a3. Hello
this
is foo

输出:

Hello
this
is foo
a[0-9]*.
-----
Hello
this
is foo
a[0-9]*.
-----

如您所见,输出将 RS 打印为表示正则表达式的字符串,但不打印实际值。如何获取记录分隔符的实际匹配值?

预期输出:

Hello
this
is foo
a1
-----
Hello
this
is foo
a3
-----

最佳答案

在 POSIX 兼容的 AWK 中,记录分隔符 RS 只是一个字符,因此很容易以 的形式调用它。

awk 'BEGIN{RS="a"}{print $0 RS}'

另一方面,GNU AWK 不限制 RS 是单字符字符串,而是允许它是任何正则表达式。在这种情况下,使用上述 AWK 变得有点棘手,因为 RS 是正则表达式而不是字符串。

为此,GNU AWK 引入了变量 RT,它仅表示找到的记录分隔符。当RS 是单个字符时,RT 包含相同的单个字符。但是,当 RS 是正则表达式时,RT 包含与正则表达式匹配的实际输入文本。

很天真,可以将您的 AWK 程序更新为:

BEGIN{RS="a[0-9]+[.] "; ORS="\n-----\n"}
/foo/{print $0 RT}

不幸的是,RT 设置为当前记录之后找到的值,并且 OP 似乎请求当前记录之前的值,因此您可以引入一个新变量 pRT 可以理解为找到前一个记录分隔符

BEGIN{RS="a[0-9]+[.] "; ORS="\n-----\n"}
/foo/{print $0 pRT}{pRT=RT}

作为Shaki Siegalcomments 中指出,您仍然需要更新 pRT 以删除最后的空格和点:

BEGIN{RS="a[0-9]+[.] "; ORS="\n-----\n"}
/foo/{print $0 pRT}{pRT=RT;sub(/[.] $/,"",pRT)}

注意:OP (RS="a[0-9]*. ") 的原始 RS 已更新为改进了与 RS="a[0-9]+[.] " 的匹配 这确保了 a 后面的数字和实际 的出现。.

如果,如原始示例所示,记录分隔符始终出现在行的开头,则应将 RS 稍微修改为 RS="(^|\n)a[ 0-9]+[.] "迪托的评论也提出了各种精彩的观点。所以如果字符串a[0-9]+。 总是出现在开头,你需要多处理一点:

BEGIN {
RS ="(^|\n)a[0-9]+[.] ";
ORS="\n-----\n"
}
/foo/ {
if (RT ~ /^$/ && NR != 2) pRT = substr(pRT,2)
print $0 pRT
}
{pRT=RT;sub(/[.] $/,"",pRT)}

在这里,我们添加了一个修正来修复最后一条记录。

  • 如果有超过两个 AWK 记录(第一个记录总是空的),你需要从 pRT 中删除第一个换行符,否则你会包含一个额外的换行符以换行符结尾的最后一条记录(与所有其他记录不同)。
  • 如果只有两个 AWK 记录(一个在文本中有效),那么您不应该进行此更正,因为第一个 RT 没有以换行符开头

最后的改进是通过意识到我们总是删除 pRT 中的初始换行符(如果存在)来完成的,因此我们可以将它们全部合并到一个 gsub 中:

BEGIN {
RS ="(^|\n)a[0-9]+[.] ";
ORS="\n-----\n"
}
/foo/ { print $0 pRT }
{pRT=RT;gsub(/^\n|[.] $/,"",pRT)}

RS: The input record separator. Its default value is a string containing a single newline character, which means that an input record consists of a single line of text. It can also be the null string, in which case records are separated by runs of blank lines. If it is a regexp, records are separated by matches of the regexp in the input text.

The ability for RS to be a regular expression is a gawk extension. In most other AWK implementations, or if gawk is in compatibility mode (see Options), just the first character of RS’s value is used.

ORS: The output record separator. It is output at the end of every print statement. Its default value is "\n", the newline character.

RT: (GNU AWK specific) The input text that matched the text denoted by RS, the record separator. It is set every time a record is read.

source: GNU AWK manual

关于awk - 使用 Gnu AWK 检索匹配的正则表达式记录分隔符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51512656/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com