【问题标题】:How can i set the delimiter as an argument in the match() function?如何将分隔符设置为 match() 函数中的参数?
【发布时间】:2020-12-12 20:10:07
【问题描述】:
awk '{while(match($0,/("[^"]+",|[^,]*,|([^,]+$))/,a)){
     $0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
     print b[1] b[4];x=0}' file

我想了解 match 子句,并想知道如何使其动态化,以便它可以将分隔符作为参数,而不是将其硬编码为逗号。

我试过了,但是因为我没有这个功能的背景,所以没有用。

awk -v dl '{while(match($0,/("[^"]+"dl|[^,]*dl|([^,]+$))/,a)){
     $0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
     print b[1] b[4];x=0}' file

输入文件数据:

a,b,c,"d,e,f",  
"a,b",c,d,"e,f",  
p,q,r,"s,u",  

所需的输出(可能是第 4 个字段):

d,e,f  
e,f  
s,u  

所需的输出(可能是第 5 个字段,因此它应该生成 3 行空白值):

在这里,分隔符可以是任何逗号、管道和所需的字段编号也是动态的..这就是为什么我想传递字段编号和分隔符的参数..
字段编号参数工作正常,但分隔符参数不行?

正如 Anubhava 所建议的,我使用的 fpat 工作得非常好,但是在从输入文件中获取第 5 列时它没有给出任何行?

【问题讨论】:

  • wrt it is not giving any rows when fetching the column 5th form the input file - 您的输入文件中没有任何第 5 列数据,您总是有 4 个字段,然后是最终的 , 然后什么都没有,所以您的第 5 列始终为空。
  • @EdMorton 感谢您的回复...实际上我已经向 Anubhava 提供了示例记录,并且在示例数据中(有问题提供)每行有 4 个分隔符,这意味着它应该有第 5 列.. 但为了使其更明显,我应该添加标题..
  • 它确实有第 5 列,只是其中没有任何数据。 - 这就是我的观点。

标签: regex shell unix awk sh


【解决方案1】:

使用gnu-awk,您可以定义一个FPAT 变量,它是匹配字段的正则表达式。

awk -v FPAT='"[^"]*"|[^,]*' '{gsub(/"/, "", $4); print $4}' file
d,e,f
e,f
s,u

从一个以分隔符作为参数的 shell 脚本运行它:

dl="${1?}"
awk -v FPAT='"[^"]*"|[^'"$dl"']*' '{gsub(/"/, "", $4); print $4}' "${2?}"

然后运行如下:

bash p.sh ',' 'file'

【讨论】:

  • 我试过这个和上面那个..但不幸的是,两者都为我返回空白..不确定是什么问题......我只是把它放在一个shell脚本中,而不是我放的文件$1 然后传递文件名..
  • 它的 4...对不起我的错.. 实际上正如上面解决方案中所建议的那样,我在您的脚本中使用了变量 dl.. 它正在产生问题.. 如果我正在使用您的解决方案,它是然后它工作得很好,但正如主要问题中所问的那样,我想将分隔符也作为变量传递..你能建议如何通过这个解决方案实现这一点
  • 是的...所以我的输入文件与上面的相同,只是我用管道替换了逗号。将其命名为 p.csv ......我的脚本是 p。 sh as --------- awk -v dl=$2 FPAT='"[^"]*"|[^"dl"]*' '{gsub(/"/, "", $4); print $4}' $1 ......... 我称它为 ..... sh p.sh p.csv "|"我也想将字段编号作为参数传递,所以我们可以设置参数而不是 $4 吗?
  • dl="${1?}" fl="${3?}" awk -v FPAT='"[^"]*"|[^'"$dl"']* ' '{gsub(/"/, "", $'"$fl"'); print $'"$fl"'}' "${2?}" 是的,这个运行良好..你能检查并确认我是否在这里犯了任何错误..你能告诉我为什么我们需要像这样定义参数,而在普通脚本中我们只是这样做 dl=$2
  • dl="${1?}"dl 设置为$1 的值,但如果$1 未传递给shell 脚本,则会返回错误。
【解决方案2】:

那个正则表达式很奇怪,所以我会重写它。正则表达式:

/("[^"]+",|[^,]*,|([^,]+$))/

"[^"]+" 被解析为 - 第一个 " 和最后一个 " 是引号,[^"]+ 匹配除引号之外的所有内容。所以它是一样的:

"([^\"]+,|[^,]*,|([^,]+$))"

我猜你想匹配一个字段[^,]+ 或一个带引号的字段\"[^\"]+\",后跟一个分隔符或行尾(,|$)。所以匹配那个。并且在匹配组中匹配字段的内部,所以匹配 \"([^\"]+)\" 或未引用的字段 ([^,]+) 然后使用这些匹配组

awk -v dl=, '{
    x = 0;
    while (match($0, "^(\"([^\"]+)\"|([^" dl "]+))(" dl "|$)", a)) {
        $0 = substr($0, RSTART + RLENGTH);
        b[++x] = a[2] a[3];   # funny, one of them will be empty
    }
    print b[4];
}' <<EOF
a,b,c,"d,e,f"
"a,b",c,d,"e,f"
p,q,r,"s,u"
EOF

d,e,f
e,f
s,u

【讨论】:

  • 感谢您分享比赛知识。这很有帮助..虽然当我用管道分隔符尝试它时,它没有用.. ---awk -v dl="|" '{ x = 0; while (match($0, "^(\"([^\"]+)\"|([^" dl "]+))(" dl "|$)", a)) { $0 = substr($0 , RSTART + RLENGTH); b[++x] = a[2] a[3]; # 有趣,其中一个是空的 } print b[4]; }' 它返回的是空白行...我是在我的最后检查,但真的需要你的帮助。
猜你喜欢
  • 1970-01-01
  • 2023-02-24
  • 2013-02-19
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
相关资源
最近更新 更多