![如何将括号之间的值复制到同一行的另一部分](https://linux22.com/image/155679/%E5%A6%82%E4%BD%95%E5%B0%86%E6%8B%AC%E5%8F%B7%E4%B9%8B%E9%97%B4%E7%9A%84%E5%80%BC%E5%A4%8D%E5%88%B6%E5%88%B0%E5%90%8C%E4%B8%80%E8%A1%8C%E7%9A%84%E5%8F%A6%E4%B8%80%E9%83%A8%E5%88%86.png)
我有一个 CSV 文件,其中包含许多行,如下所示:
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,L0480,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,L0481,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,L0487,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
...
我需要做的是,如果第五列(
以复制括号之间的值代替第三列开始。如果没有,请保持线路不变。
所以结果是:
1003,CC,LB1,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
...
我正在考虑用 来做这件事sed
,我知道我可以捕获括号之间的部分,但我不知道如何替换未知的文本。
可以用 来做吗sed
?
答案1
假设您的 CSV 没有嵌入分隔符(包含引号逗号的逗号分隔字段),那么使用 Awk 就很简单:
$ awk 'BEGIN{OFS=FS=","} match($5,/^\([0-9]+\)/) {$3 = substr($5,RSTART+1,RLENGTH-2)} 1' file.csv
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
使用 Sed(具有相同的限制):
$ sed -E 's/^([^,]*),([^,]*),([^,]*),([^,]*),\(([0-9]+)\)/\1,\2,\5,\4,(\5)/' file.csv
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
更稳健的是,使用 perl 的 Text::CSV 模块:
$ perl -C -MText::CSV -lne '
BEGIN{$p = Text::CSV->new()}
@f = $p->fields() if $p->parse($_);
$f[2] = $1 if $f[4] =~ /^\((\d+)\)/;
print join ",", @f
' file.csv
1003,CC,L1008,,(LB1) Urbà de Barberà del Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781) St. Vicenç Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784) Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783) Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
答案2
为什么不用Python呢? (将文件名替换为您的文件名)
import re, csv
for line in list(csv.reader(open('filename', 'r'))):
matches = re.findall('\([0-9]*\)',line[4])
if matches:
line[2] = matches[0]
print(','.join(line))
答案3
通过下面的脚本完成
count=`awk '{print NR}' filename| sort -nr| sed -n '1p'`
for ((i=1;i<=$count;i++)); do h=`awk -v i="$count" -F "," 'NR==i && $5 ~ /^\(/{print $5}' filename | awk '{print $1}'| sed -e "s/(//g" -e "s/)//g"| wc -l`; if [[ $h != 0 ]]; then k=`awk -v i="$count" -F "," 'NR==i && $5 ~ /^\(/{print $5}' filename | awk '{print $1}'| sed -e "s/(//g" -e "s/)//g"`; awk -v i="$count" -v k="$k" -F "," 'NR==i && $5 ~ /^\(/{$3=k;print $0}' filename| sed "s/ /,/g"; else awk -v i="$count" 'NR==i {print $0}' filename; fi; done
输出
1003,CC,LB1,,(LB1),Urbà,de,Barberà,del,Vallès,3,,,
1006,CK,L0520,,Móra d'Ebre - Móra la Nova (estació),3,,,
1007,AV,L0358,,Granollers-Terrassa-Manresa,3,,,
1011,DD,781,,(781),St.,Vicenç,Castellet-Castellgalí-Manresa,3,,,
1012,DD,784,,(784),Manresa-Castellgalí-St.Vicenç-Monistrol,3,,,
1013,DD,783,,(783),Manresa-Pt.Vilomara-St.Vicenç-Monistrol,3,,,
答案4
的awk
和sed
版本钢铁起子提供的工作就像一个魅力,并且在我当前的环境中非常容易实现。
我对它们进行了一些改进,允许括号之间的代码中包含字母、空格和点:
awk 'BEGIN{OFS=FS=","} match($5,/^\([a-zA-Z0-9 .]+\)/) {$3 = substr($5,RSTART+1,RLENGTH-2)} 1' file.csv
sed -E 's/^([^,]*),([^,]*),([^,]*),([^,]*),\(([a-zA-Z0-9 .]+)\)/\1,\2,\5,\4,(\5)/' file.csv
其他版本也可以工作,但不太适合我正在做的工作流程。
谢谢!