繁体   English   中英

带有正则表达式的 awk 中的自定义字段分隔符:前导空格和逗号问题

[英]Custom field separators in awk with regex: problem with leading spaces and commas

我在 stackoverflow 上四处寻找解决方案,我找到了一些相关的答案,但我一直无法找到明确的解决方案来解决我的疑问。 我希望我不会问重复的问题。

让我们考虑一个文件

cat > file << EOF
1 2  3 4, 5,, 6, 7
EOF

我想使用任意数量的逗号和空格作为分隔符。 使用 awk,用 F"[ ,]*" 设置字段分隔符,我得到了想要的结果,即:

awk -F"[ ,]+" '{print $1}' file --> 1
awk -F"[ ,]+" '{print $2}' file --> 2
awk -F"[ ,]+" '{print $3}' file --> 3
awk -F"[ ,]+" '{print $4}' file --> 4
awk -F"[ ,]+" '{print $5}' file --> 5
awk -F"[ ,]+" '{print $6}' file --> 6
awk -F"[ ,]+" '{print $7}' file --> 7

但是,如果我有前导空格,我就会遇到问题。 例如:

有一个领先的空间

cat > file << EOF
 1 2  3 4, 5,, 6, 7
EOF

我得到

awk -F"[ ,]+" '{print $1}' file -->   
awk -F"[ ,]+" '{print $2}' file --> 1
awk -F"[ ,]+" '{print $3}' file --> 2
...

两个前导空格相同

cat > file << EOF
  1 2  3 4, 5,, 6, 7
EOF
awk -F"[ ,]+" '{print $1}' file -->  
awk -F"[ ,]+" '{print $2}' file -->  1
awk -F"[ ,]+" '{print $3}' file -->  2
...

等等。

然而,问题不仅在于空间。 例如与

cat > file << EOF
1,2,3,
EOF

我有

awk -F"," '{print $1}' file -->   1
awk -F"," '{print $2}' file -->   2
awk -F"," '{print $3}' file -->   3
awk -F"," '{print $4}' file -->  

这是我所期望的,但与

cat > file << EOF
,1,2,3
EOF

我得到

awk -F"," '{print $1}' file -->   
awk -F"," '{print $2}' file -->   1
awk -F"," '{print $3}' file -->   2
awk -F"," '{print $4}' file -->   3

我不明白为什么。

awk 似乎以不同的方式处理前导分隔符。 可能,我误解了正则表达式语法。 事实上,我不明白为什么设置 -F"" 前导空格会以正确的方式处理,而设置 -F"[ ]*" 我有同样的问题。

总之,这些是我的问题:为什么我会获得前导空格或前导逗号的这些结果,以及要考虑的正确语法是什么,作为字段分隔符,任意数量的逗号和空格,无论它们是否前导。

是的,有一些不一致,我想是为了方便。

默认分隔符忽略前导/尾随空格

$ echo " 1 2 " | awk '{for(i=1;i<=NF;i++) print i"--> "$i}'
1--> 1
2--> 2

FS设置为 space 的行为相同

$ echo " 1 2 " | awk -F' ' '{for(i=1;i<=NF;i++) print i"--> "$i}'
1--> 1
2--> 2

但是,字符集。

$ echo " 1 2 " | awk -F'[ ]' '{for(i=1;i<=NF;i++) print i"--> "$i}'
1-->
2--> 1
3--> 2
4-->

因为有 3 个分隔符(所以假设有四个字段)。 使用逗号分隔符,您将不会获得默认行为,而只会获得最后一个版本。

如果你想模仿逗号和空格的默认行为,你需要编写自己的处理方式,像这样

$ echo "   ,1 2," | 
  awk -F'[ ,]+' 'NF{if($1=="") {for(i=2;i<=NF;i++) $(i-1)=$i; NF--} 
                    if($NF=="") NF--} 
                   {for(i=1;i<=NF;i++) print i"--> "$i}'

1--> 1
2--> 2

说明:如果第一个字段为空,则将所有字段左移一位,字段数减一; 同样,如果最后一个字段为空,只需减少字段数。 最后一条语句用于按字段位置编号一行打印字段。

在尝试修复字段之前,更新以处理空行添加保护NF

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM