Unix: ค้นหาและแทนที่เครื่องหมายจุลภาคที่ต่อเนื่องกันเป็นไปป์ไลน์ที่ต่อเนื่องกัน

Jan 08 2021

ฉันกำลังแปลง CSV ที่ยกมาสองครั้งเป็นไฟล์ txt ที่คั่นด้วยไปป์ไลน์ใน Unix ฉันใช้คำสั่ง sed ต่อไปนี้เพื่อแทนที่ "," เป็น | จากนั้นลบเครื่องหมายคำพูดคู่เริ่มต้นและสิ้นสุด

sed -e 's/","/|/g' -e 's/"//g' filenm.csv > filenm.txt

แต่ดูเหมือนว่าไฟล์จะมีเครื่องหมายจุลภาคติดต่อกันโดยไม่มีเครื่องหมายอัญประกาศคู่และไม่มีการแทนที่

Col1|col2|col3|col4|col5|col6|col7|col8
Val1|val2|val3,,,,val7|val8

ตอนนี้ฉันต้องการแปลงเครื่องหมายจุลภาคต่อเนื่องกันทั้งหมดนี้เป็นไปป์ไลน์ที่ต่อเนื่องกันเนื่องจากระบุว่าช่องว่างหรือว่าง

และเขตข้อมูลอื่น ๆ ยังมีเครื่องหมายจุลภาคภายในค่าเขตข้อมูลซึ่งไม่ควรเปลี่ยนแปลง

ฉันลองใช้ด้านล่างสำหรับสิ่งนั้น แต่ไม่ได้ผล

sed -e 's/,{1,\}/|{1,\}/g' filenm.csv > filenm.txt

ไฟล์ csv ตัวอย่างที่เปิดใน notepad:

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

ฉันหวังว่านี่จะช่วยทำให้ปัญหาเกิดซ้ำและแก้ไขได้

ขอบคุณล่วงหน้า....

คำตอบ

2 WiktorStribiżew Jan 08 2021 at 22:37

คุณสามารถใช้perl:

perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' filenm.csv > filenm.txt

รายละเอียด :

  • "([^"]*)"|,- รูปแบบนิพจน์ทั่วไปที่จับคู่"จากนั้นจับเป็นกลุ่ม 1 อักขระใด ๆ ที่เป็นศูนย์หรือมากกว่านอกเหนือ"จากนั้นจับคู่ a "หรือจับคู่กับ,ในบริบทอื่น ๆ ทั้งหมด
  • defined($1) ? $1 : "|"- RHS การแทนที่ซึ่งแทนที่การจับคู่ด้วยค่ากลุ่ม 1 (ถ้าจับคู่กลุ่ม 1) หรือด้วย|(ถ้า,ตรงกัน)
  • ge- gย่อมาจากglobal(แทนที่เหตุการณ์ทั้งหมด) และeทำให้ Perl ถือว่า RHS เป็นนิพจน์ Perl

ดูการทดสอบออนไลน์ :

#!/bin/bash
s='"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","0","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"'
perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' <<< "$s"

เอาท์พุต:

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|0|No.38,3rd st, RRR NNN, TRT||||9999999999
4 potong Jan 08 2021 at 23:05

สิ่งนี้อาจได้ผลสำหรับคุณ (GNU sed):

sed -E ':a;s/^(("[^",]*",+)*"[^",]*),/\1\n/;ta;y/,\n/|,/' file

ซ้ำแทนที่,'s ระหว่าง"' S กับการขึ้นบรรทัดใหม่แล้วแปล,'s สำหรับ|' s และการขึ้นบรรทัดใหม่สำหรับ,'s

1 RamanSailopal Jan 09 2021 at 00:35

ใช้ awk:

awk -F \" '{ for(i=1;i<=NF;i++) { if ($i ~ /^[,]{2,}$/) { $i="," } } OFS="\"";gsub("\",\"","\"|\"",$0)}1' sample.csv

คำอธิบาย:

awk -F \" '{  # Set the field delimiter to double quote
             for(i=1;i<=NF;i++) { 
               if ($i ~ /^[,]{2,}$/) { 
                  $i="," # Loop through each field and if is contains 2 or more commas, set that field to one comma } } OFS="\""; gsub("\",\"","\"|\"",$0) # Substitute "," for "|"
           }1' sample.csv
1 Daweo Jan 09 2021 at 01:50

ฉันจะใช้ GNU AWKสำหรับวิธีต่อไปนี้ ให้file.txtเนื้อหาเป็น

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

แล้ว

awk 'BEGIN{FS="\"";OFS=""}{for(i=1;i<=NF;i+=2){$i=gensub(/,/,"|","g",$i)};print $0}' file.txt

เอาท์พุท

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|15|No.38,3rd st, RRR NNN, TRT||||9999999999
456|DEF|12/20/2020|||||test-country|9999999999
465|XYZ|||No.38,3rd st, RRR NNN, TRT||||9999999999

ฉันคิดว่าคอลัมน์แรกและคอลัมน์สุดท้ายจะไม่ว่างเปล่า ผมใช้"เป็นตัวคั่นฟิลด์และจากนั้นในฟิลด์คี่ทุก (เหล่านี้มี แต่เพียงผู้เดียว,) ฉันเปลี่ยนแปลงตลอดไป, |ในที่สุดฉันก็พิมพ์บรรทัดที่เปลี่ยนแปลงดังกล่าวทั้งหมด

(ทดสอบใน GNU Awk 5.0.1)