如何使用正则表达式和shell脚本(sed或awk,更可取)替换字符串中的某些字符[已关闭]

7uzetpgm  于 2023-03-24  发布在  Shell
关注(0)|答案(2)|浏览(129)

已关闭。此问题需要超过focused。当前不接受答案。
**想要改进此问题吗?**更新此问题,使其仅关注editing this post的一个问题。

12小时前关门了。
Improve this question
我有一个用管道分隔的简单文本文件。
行示例:

a|b|c|d|0|e|f|g

然而,一些天才使用其中一列中的管道作为数据的一部分,生成以下内容:

a|b|c|d|"1|2|3"|e|f|g
a|b|c|d|"1|2"|e|f|g
a|b|c|d|"1|2|3|4|5"|e|f|g

从本质上讲,引号之间的任何内容都将被视为一个单独的值,但是加载到数据库的脚本将这些管道中的每一个都解释为字段分隔符。
我需要编写一个shell脚本,将引号之间的管道转换为另一个字符(例如,分号),生成以下转换后的数据:

a|b|c|d|"1;2;3"|e|f|g
a|b|c|d|"1;2"|e|f|g
a|b|c|d|"1;2;3;4;5"|e|f|g

如果有人有想法,正则表达式将是首选。

rsl1atfo

rsl1atfo1#

假设你引用的字段不包含换行符,这看起来极不可能,因为你提供了一个例子,你说“我有一个简单的文本文件是管道分隔的。”,你所需要的就是下面的,在每个Unix机器上的任何shell中使用任何awk:

$ awk 'BEGIN{FS=OFS="\""} {for (i=2; i<=NF; i+=2) gsub(/\|/,";",$i); print}' file
a|b|c|d|"1;2;3"|e|f|g
a|b|c|d|"1;2"|e|f|g
a|b|c|d|"1;2;3;4;5"|e|f|g

另请参见whats-the-most-robust-way-to-efficiently-parse-csv-using-awk
我知道你说“正则表达式将是首选”,从技术上讲,上面确实使用了正则表达式,但可能不是以你期望的方式,所以请记住这句话:
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.

anhgbhbe

anhgbhbe2#

使用正则表达式替换字符串中的某些字符
如果你想这样做,那么我提出以下解决方案,它利用了perl的正面外观特性,让file.txt内容

a|b|c|d|"1|2|3"|e|f|g|"7|8|9"
a|b|c|d|"1|2"|e|f|g|"7|8|9"|h
a|b|c|d|"1|2|3|4|5"|e|f|g

那么

perl -p -e 's/[|](?=[^"]*"[^"]*("[^"]*"[^"]*)*$)/;/g' file.txt

给出输出

a|b|c|d|"1;2;3"|e|f|g|"7;8;9"
a|b|c|d|"1;2"|e|f|g|"7;8;9"|h
a|b|c|d|"1;2;3;4;5"|e|f|g

说明:-p -e表示使用sed模式,然后全局I(g)替换|当且仅当它后跟 * 奇数 * 个零或更多的非"后跟"运行,注意[^"]*"[^"]*总是保持1 ""[^"]*"[^"]*保持2 ",所以[^"]*"[^"]*("[^"]*"[^"]*)*总是保持 1 + 2n",其中 n 是正整数。请记住$是至关重要的,否则你会发现 * 奇数 * 在每个非零 * 偶数 * 的"的数字。
注意:我稍微修改了你的文件,以测试更复杂的情况。

  • (在perl 5,version 30,subversion 0中测试)*

相关问题