【发布时间】:2023-03-11 17:40:02
【问题描述】:
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 来解决字段问题,因为将否定匹配正则表达式写入 \" 似乎并没有那么糟糕。
我来到this answer to Regular expression to match a line that doesn't contain a word 时有一个指向(非现场链接)an online generator of negative regular expressions given an input phrase 的链接。
由于生成器目前仅支持字母数字和空格字符,\"(反斜杠引号)被替换为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
这是对的。将生成的程序中的pqs 替换为|"s:
$ 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
这仍然是正确的。但是,当用\s 替换bs 并添加一些转义时,导致:
(TL;DR如何在下面的脚本中修复转义)
$ gawk 'BEGIN {
FPAT="([^|]*)|(\\\"([^\\]|\\+[^\\\"])*\\*\\\")"
OFS=ORS
}
{
print $1,$2,$3,$4
}' data
并且输出失败或与之前不同:
1
\"2\"
\"3.1
3.2\"
所以我的\\s 可能有问题,但经过多次尝试和错误后,我的脑海中充满了反斜杠,所有的想法几乎都逃脱了(双关语)。由于社区都是关于分享的,所以我想与你们分享我的头痛。
编辑:显然它与引号中的反斜杠有关,因为如果不是定义FPAT="...",而是使用GNU awk's strongly typed 输入FPAT=@/.../,我会得到正确的输出:
$ gawk 'BEGIN {
FPAT=@/([^|]*)|(\\\"([^\\]|\\+[^\\\"])*\\*\\\")/
OFS=ORS
}
{
print $1,$2,$3,$4
}' data
现在输出:
1
\"2\"
\"3.1|3.2\"
4
【问题讨论】:
-
关于
Edit: Apparently it's got something to do with backslashes in quotes- idk,如果你逃避事情的方式有任何其他问题,但这不是你遇到的问题,这正是我在回答中所说的,@987654356 @ 不代表not \"。我尝试在你的最后一个代码段中使用 FPAT,但得到了awk: tst.awk:2: warning: regexp escape sequence `\"' is not a known regexp operator所以我知道你想在那里发布什么。 -
有趣。我最近在使用
sub(/\"/...)时也收到了同样的警告,以上所有部分都没有给我这样的警告。如果有意义的话,感觉就像是突然开始的。 -
再次 -
[^\\\"]表示neither the char \ nor the char "当您需要一些表示not the string \"的东西时,BRE 或 ERE 中不存在这样的结构,这就是为什么您必须将每个\"转换为一个字符X然后你可以写[^X],就像我的答案一样,我使用\n表示X。当然,您可以使用其他一些正则表达式从发布的示例输入中获得预期的输出,但是如果给定其他输入,它将失败,例如包含单个\或单个"的输入,例如\"foo"bar\here\" -
我明白了。
-
您应该从
sub(/\"/...)收到警告,因为该正则表达式要么试图转义文字字符,要么试图指定文字\但忘记转义它 - 在任何一种情况下,正则表达式都是错误,它应该是sub(/"/,...)或sub(/\\"/,''')并且该工具不理解您要说的内容,因此它会猜测您想要前者并警告您这样做。