Regex gawk–有条件(即,取决于正则表达式匹配)查找/替换为某些转换器函数

Regex gawk–有条件(即,取决于正则表达式匹配)查找/替换为某些转换器函数,regex,search,command-line,replace,awk,Regex,Search,Command Line,Replace,Awk,我的输入文件是 input.txt: 您可以在第6行看到奇怪的时间格式,但这只是为了演示,目的是简化逻辑,而不需要额外的0-59要求 我想对每一行应用以下正则表达式: ^(.*?)\sA\s(.*?)\sB\s(.*?)\sC\s(.*?)$ 请注意\3的语法。有效变体: \d{1,}h\d{1,}m\d{1,}s \d{1,}m\d{1,}s \d{1,}s \d{1,}等于\d{1,}s 我需要将其转换为秒数,但如果此部件未能通过此验证,请保持原样。无论如何,让我们将结果命名为$sec

我的输入文件是

input.txt:

您可以在第6行看到奇怪的时间格式,但这只是为了演示,目的是简化逻辑,而不需要额外的0-59要求

我想对每一行应用以下正则表达式:

^(.*?)\sA\s(.*?)\sB\s(.*?)\sC\s(.*?)$  
请注意\3的语法。有效变体:

\d{1,}h\d{1,}m\d{1,}s \d{1,}m\d{1,}s \d{1,}s \d{1,}等于\d{1,}s 我需要将其转换为秒数,但如果此部件未能通过此验证,请保持原样。无论如何,让我们将结果命名为$sec

我需要定义以下正则表达式变量:

$price=='\d{1,}',$names='Bob | Tom |劳拉| Sandra',$tags=='News | Show'或?:正则表达式语法,我不知道这里哪个更好

然后,将管路更换为以下部件:

如果\1~$price:

ID:\1;时间:秒;说明:\1–以$1购买

如果\1~$names:

描述:\4 from@\1;时间:$秒

如果\1~$标记:

ID:\2\1.时间:秒;说明:\4

否则,如果\1与任何预定义的正则表达式变量不匹配,或与多个变量匹配:

ID:\2;时间:秒\1.说明:\4

所以输出文件应该是

output.txt:

我使用了以下代码:

gawk -F '\\|' 'function _time(str) {
if (str ~ /([[:digit:]]+)h\s([[:digit:]]+)m\s([[:digit:]]+)s/ ) {
match(str, /([[:digit:]]+)h\s([[:digit:]]+)m\s([[:digit:]]+)s/, arr)
return arr[1]*3600+arr[2]*60+arr[3] }
else if (str ~ /([[:digit:]]+)m\s([[:digit:]]+)s/ ) {
match(str, /([[:digit:]]+)m\s([[:digit:]]+)s/, arr)
return arr[1]*60+arr[2] }
else if (str ~ /([[:digit:]]+)s/ || str ~ /([[:digit:]]+)/) {
match(str, /([[:digit:]]+).*?/, arr)
return arr[1] }
else 
return str } 
match($0, /^(.*?)\sA\s(.*?)\sB\s(.*?)\sC\s(.*?)$/, _f) 
{ if (_f[1] ~ /[[:digit:]]+/) {
printf "ID: %s; time: %s seconds; description: %s – buy for $%s\n", _f[2], _time(_f[3]), _f[4], _f[1] }
else if (_f[1] ~ /Bob|Tom|Laura|Sandra/) {
printf "description: %s from %s; time: %s seconds\n", _f[4], _f[1], _time(_f[3]) }
else if (_f[1] ~ /News|Show/) {
printf "ID: %s; #%s; time: %s seconds; description: %s\n", _f[2], _f[1], _time(_f[3]), _f[4] }
else {
printf "ID: %s; time: %s seconds; %s; description: %s\n", _f[2], _time(_f[3]), _f[1], _f[4] } }' input.txt > output.txt.
有四个问题

为什么我看到输入行在输出行之前?我想用结果行替换输入行! 为什么我在第八条输出线上看到0秒?我希望看到0:30秒。为什么0:30匹配/[[:digit:]+s/| |/[:digit:]+/?我希望else return str在这里运行,保持0:30不变。 我使用if\u f[1]~/regex/语法,但我不知道如何将/regex/放入变量中。当我把它放入变量中时,它就不起作用了。 我不知道AWK是如何工作的。它能测试所有条件吗?如果是,当f[1]匹配多个条件时,如果f[1]~/X | A/{…}或者如果f[1]~/A | B/{…},它应该怎么做?我想把这个案子放到别的地方。如果没有,我将选择立即打印第一场比赛的结果,以提高性能。 附加说明:我使用的是Cygwin命令行,没有为代码使用单独的.awk文件。

尝试设置FS:

awk '{print "timestamp:", $3}' FS=' (A|B|C) ' input.txt

哪个版本的gawk?对于0:30,它与上一个regex/[[:digit:][]+/匹配,因为0是一个数字,您可以使用一个或多个数字进行测试。通过为正则表达式指定start和end,您可能会得到更好的结果,例如:/^[[:digit:][]+$/用于创建捕获组的括号在比较中是无用的。在接下来的测试中,我将进行测试,首先它在我的gawk版本3.1.7上不起作用。我看不见树木,看不见森林。我想您的主要问题是如何将人类可读的时间戳转换为秒,不是吗?您可以不使用/regex/,而使用匹配$0,regex@Jdamian:事实上,没有。绝对没有。时间转换器只是一个简单的例子,主要问题是如何将任何函数的结果与if/else逻辑相结合。我解决了所有这些问题,除了一个,但我会作为一个明确的、单独的问题来问这个问题
gawk -F '\\|' 'function _time(str) {
if (str ~ /([[:digit:]]+)h\s([[:digit:]]+)m\s([[:digit:]]+)s/ ) {
match(str, /([[:digit:]]+)h\s([[:digit:]]+)m\s([[:digit:]]+)s/, arr)
return arr[1]*3600+arr[2]*60+arr[3] }
else if (str ~ /([[:digit:]]+)m\s([[:digit:]]+)s/ ) {
match(str, /([[:digit:]]+)m\s([[:digit:]]+)s/, arr)
return arr[1]*60+arr[2] }
else if (str ~ /([[:digit:]]+)s/ || str ~ /([[:digit:]]+)/) {
match(str, /([[:digit:]]+).*?/, arr)
return arr[1] }
else 
return str } 
match($0, /^(.*?)\sA\s(.*?)\sB\s(.*?)\sC\s(.*?)$/, _f) 
{ if (_f[1] ~ /[[:digit:]]+/) {
printf "ID: %s; time: %s seconds; description: %s – buy for $%s\n", _f[2], _time(_f[3]), _f[4], _f[1] }
else if (_f[1] ~ /Bob|Tom|Laura|Sandra/) {
printf "description: %s from %s; time: %s seconds\n", _f[4], _f[1], _time(_f[3]) }
else if (_f[1] ~ /News|Show/) {
printf "ID: %s; #%s; time: %s seconds; description: %s\n", _f[2], _f[1], _time(_f[3]), _f[4] }
else {
printf "ID: %s; time: %s seconds; %s; description: %s\n", _f[2], _time(_f[3]), _f[1], _f[4] } }' input.txt > output.txt.
awk '{print "timestamp:", $3}' FS=' (A|B|C) ' input.txt