删除第一个和最后一个双引号(最好是 sed/awk)

Removing first and last double quote (preferably sed/awk)

提问人:ak1234 提问时间:11/16/2023 更新时间:11/17/2023 访问量:94

问:

我只想删除第一个和最后一个双引号

输入:

word1 -word2 {word3} -word4 {"word5 'word6' "word7 word8" .word9"} -word10 (word11)
word1 -word2 {word3} -word4 {"word5 'word6' word7 word8 .word9"} -word10 (word11)
word1 -word2 {word3} -word4 {"word5 'word6' "word7 (word8)" .word9"} -word10 (word11)

预期输出:

word1 -word2 {word3} -word4 {word5 'word6' "word7 word8" .word9} -word10 (word11)
word1 -word2 {word3} -word4 {word5 'word6' word7 word8 .word9} -word10 (word11)
word1 -word2 {word3} -word4 {word5 'word6' "word7 (word8)" .word9} -word10 (word11)

尝试删除第一个 但不起作用

sed 's/"\({\)/\1/g' inputfile > outputfile

删除行中的第一个双引号,即可以接受“{”之后和“}”之前。

假设单词的长度也可以不同。

评论

3赞 Renaud Pacalet 11/16/2023
怎么样?sed 's/"\(.*\)"/\1/'
0赞 Kais 11/16/2023
试试这个: sed 's/“({[^}]*})”/\1/g' 输入文件 > 输出文件
1赞 pmf 11/16/2023
如果第一行在第一行之前(分别在最后一行、之后、 )怎么办?"{}
1赞 jhnc 11/16/2023
如果只有一个双引号怎么办?还是奇数?
0赞 Ed Morton 11/16/2023
在正则表达式中,,位于 之前。在您的数据中,位于 .顺序在模式匹配中很重要。/"\({\)/"{{"

答:

3赞 anubhava 11/16/2023 #1

您可以将此 sed 与捕获组一起使用:

sed -E 's/\{"(.*)"}/{\1}/' file

word1 -word2 {word3} -word4 {word5 'word6' "word7 word8" .word9} -word10 (word11)
word1 -word2 {word3} -word4 {word5 'word6' word7 word8 .word9} -word10 (word11)
word1 -word2 {word3} -word4 {word5 'word6' "word7 (word8)" .word9} -word10 (word11)

这里的模式匹配 和 之间的最长匹配,并将中间的捕获测试捕获到捕获组中。{"(.*)"}{""}

评论

1赞 Ed Morton 11/16/2023
FWIW 你不需要转义 .}
0赞 anubhava 11/16/2023
}仍然被认为是正则表达式元字符。如果我调用 Python,它会给出:即两者都转义了。re.escape('{}')\{\}
0赞 Ed Morton 11/16/2023
不是在您正在使用的 ERE 中 - 如果它之前有一个 RE 间隔打开,则只是一个 metachar,就像跟随与否一样。在 POSIX 中,在任何其他上下文中都是未定义的行为(就像几乎任何其他字符一样),但我希望通常会被视为字面意思,因此可能不会真正造成任何伤害。也许 python 假设 PCRE?我不知道PCRE规则是什么。}{)(\}\
1赞 Ed Morton 11/16/2023
现在看看 pubs.opengroup.org/onlinepubs/9699919799/basedefs/......它说:“一个普通的角色是一个与自己相匹配的 ERE。普通字符是受支持的字符集中的任何字符,但 ERE 特殊字符中列出的 ERE 特殊字符除外。以未转义的<反斜杠> ( '\\' ) 开头的普通字符的解释是未定义的,除非在括号表达式的上下文中”。因此,是一个普通字符,因此在这种情况下的解释是不确定的。}\}
1赞 anubhava 11/17/2023
谈论PCRE回报preg_quote('/}/')/\}/
2赞 RavinderSingh13 11/16/2023 #2

第1种解决方案:对于您展示的示例,请尝试以下 GNU 代码。使用函数,其中使用正则表达式创建 3 个捕获组并将其值保存到名为 arr 的数组中,如果找到真正的匹配项,则只需打印数组的所有值即可获得所需的输出。awkmatch(^.*{)"(.*)"(}.*$)

awk 'match($0,/(^.*{)"(.*)"(}.*$)/,arr){print arr[1] arr[2] arr[3]}' Input_file

这是使用正则表达式的在线演示

第二种解决方案:或者,如果您的数据与所示样本相同,并且每行仅出现 1 次,则尝试以下操作。{""}

awk '{sub(/{"/,"{");sub(/"}/,"}")} 1'  Input_file
1赞 Daweo 11/17/2023 #3

我会利用 GNU 来完成这个任务,让内容成为AWKfile.txt

word1 -word2 {word3} -word4 {"word5 'word6' "word7 word8" .word9"} -word10 (word11)
word1 -word2 {word3} -word4 {"word5 'word6' word7 word8 .word9"} -word10 (word11)
word1 -word2 {word3} -word4 {"word5 'word6' "word7 (word8)" .word9"} -word10 (word11)

然后

awk 'BEGIN{FPAT="\"|[^\"]*";OFS=""}{$2=$(NF-1)="";print}' file.txt

给出输出

word1 -word2 {word3} -word4 {word5 'word6' "word7 word8" .word9} -word10 (word11)
word1 -word2 {word3} -word4 {word5 'word6' word7 word8 .word9} -word10 (word11)
word1 -word2 {word3} -word4 {word5 'word6' "word7 (word8)" .word9} -word10 (word11)

解释:我告诉 GNU,字段要么是单个的,要么是零或多个非的,输出中的字段之间不应该添加任何内容。然后,对于每一行,我将第二个字段(第一个)和最后一个字段(最后一个)之前的字段设置为空字符串,即删除它。免责声明:此解决方案假定从来都不是第一行的最后一个字符,也绝不是最后一行的字符。AWK""""""

(在 GNU Awk 5.1.0 中测试)