TL(请参见问题结尾的 TL;DR)
我使用管道符号作为字段分隔符(|
),并使用反斜杠加引号对(\"
)来引用数据中包含分隔符的字段,例如:
1|\"2\"|\"3.1|3.2\"|4 # basically 1, 2, 3.1|3.2, 4
那就是(在awk中):
$1==1
$2==\"2\"
$3==\"3.1|3.2\"
$4==4
我决定尝试使用GNU awk的FPAT来解决字段问题,因为编写一个否定匹配正则表达式到
\"
似乎并不那么糟糕。我找到了这个回答Regular expression to match a line that doesn't contain a word,其中包含一个链接到(外部链接)给定输入短语的负正则表达式在线生成器。
由于该生成器目前仅支持字母数字和空格字符,因此将
\"
(反斜线引号)替换为bq
,生成器提供了正则表达式:^([^b]|b+[^bq])*b*$
|
被替换为p
,上面的数据被替换为:
1pbq2bqpbq3.1p3.2bqp4
1|\"2\"|\"3.1|3.2\"|4 # original for comparision
样例来自GNU Awk文档的FPAT
(FPAT="([^,]*)|(\"[^\"]+\")"
),被用来生成一个FPAT
:
FPAT="([^p]*)|(bq([^b]|b+[^bq])*b*bq)"
一项试验已经完成:
$ gawk 'BEGIN {
FPAT="([^p]*)|(bq([^b]|b+[^bq])*b*bq)"
OFS=ORS
}
{
print $1,$2,$3,$4
}' data
输出结果为:
1
bq2bq
bq3.1p3.2bq
4
这是正确的。在程序中用|"
替换pq
后得到:
$ gawk 'BEGIN {
FPAT="([^|]*)|(b\"([^b]|b+[^b\"])*b*b\")"
OFS=ORS
}
{
print $1,$2,$3,$4
}' data
输出:
1
b"2b"
b"3.1|3.2b"
4
这段代码原本是正确的,但是当用\
替换b
并添加转义字符后,结果如下:
(简短总结如何修复以下脚本中的转义问题)
$ gawk 'BEGIN {
FPAT="([^|]*)|(\\\"([^\\]|\\+[^\\\"])*\\*\\\")"
OFS=ORS
}
{
print $1,$2,$3,$4
}' data
并且输出失败或与之前不同:
1
\"2\"
\"3.1
3.2\"
我猜测我的\\
有问题,但经过多次尝试和错误,我的脑海里充满了反斜杠,所有的想法几乎都逃脱了(双关语)。由于社区是关于分享的,我想与你们分享我的头痛。
编辑:显然这与引号中的反斜杠有关,因为如果我使用GNU awk的强类型类型FPAT=@/.../
来定义,而不是定义FPAT="..."
,我会得到正确的输出:
$ gawk 'BEGIN {
FPAT=@/([^|]*)|(\\\"([^\\]|\\+[^\\\"])*\\*\\\")/
OFS=ORS
}
{
print $1,$2,$3,$4
}' data
现在输出:
1
\"2\"
\"3.1|3.2\"
4
编辑:显然这与引号中的反斜杠有关
- 我不知道你在转义方面是否还有其他问题,但这不是你遇到的问题,正如我在答案中所说的那样,[^\\\"]
并不意味着not \"
。我尝试在您最后的代码段中使用FPAT,但是得到了awk:tst.awk:2:警告:regexp转义序列`\"'不是已知的regexp运算符
,所以我不知道您想发布什么。 - Ed Mortonsub(/\"/...)
时,我也收到了同样的警告,但上面的代码段都没有出现过这种情况。感觉好像突然就开始出现了,如果有任何意义的话。 - James BrownFPAT="...\\..."
)而不是正则表达式中(FPAT=@/...\\.../
)时,预计会有不同的转义次数结果,因为它在使用时会被评估两次,一次在转换为正则表达式时,另一次在作为该正则表达式时使用。这就是为什么printf 'a\\b\n' | awk '{sub("\\\\","-")}1'
(或printf 'a\\b\n' | awk '{x="\\\\"; sub(x,"-")}1'
)需要两次转义,而printf 'a\\b\n' | awk '{sub(/\\/,"-")}1'
只需要一次转义的原因。 - Ed Morton