ลบเฉพาะเครื่องหมายจุลภาคที่อยู่ในเครื่องหมายคำพูดคู่


10

ในไฟล์ข้อความฉันต้องการลบ,(เครื่องหมายจุลภาค) และ"(เครื่องหมายคำพูด) (เฉพาะเมื่อเครื่องหมายคำพูดคู่มีตัวเลขคั่นด้วยเครื่องหมายจุลภาค)

56,72,"12,34,54",x,y,"foo,a,b,bar"

ouput ที่คาดหวัง

56,72,123454,x,y,"foo,a,b,bar"

หมายเหตุ:ฉันแสดงบรรทัดด้านบนเป็นตัวอย่าง ไฟล์ข้อความของฉันมีหลายบรรทัดเหมือนด้านบนและตัวเลขที่คั่นด้วยเครื่องหมายจุลภาคที่อยู่ในเครื่องหมายคำพูดคู่ควรเปลี่ยนไป นั่นคือ,

56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"

ผลลัพธ์ที่คาดหวัง:

56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

มีnตัวเลขอยู่ในเครื่องหมายคำพูดคู่คั่นด้วยเครื่องหมายจุลภาค และยังเว้นเครื่องหมายคำพูดคู่ซึ่งมีอักขระเหมือนเดิม

ฉันรักsedเครื่องมือประมวลผลข้อความ ฉันดีใจที่คุณโพสต์sedวิธีแก้ปัญหาสำหรับเรื่องนี้


จาก56,72,"12,34,54",x,y,"foo,a,b,bar"การ56,72,123454,x,y,"a,b", fooและbarมีที่หายไป มันเป็นผลลัพธ์ที่คุณต้องการ?
cuonglm

ตัวอย่างที่คุณใช้มีความสับสนเล็กน้อยเนื่องจากองค์ประกอบบางอย่าง (เช่นfooและbar) ถูกลบพร้อมกับเครื่องหมายจุลภาค นอกจากนี้คำพูดบางคำก็หายไป ไม่ต้องพูดถึงว่าจุลภาคระหว่างaและbยังคงอยู่เช่นกัน มีรูปแบบใดบ้างสำหรับสิ่งเหล่านี้?
HalosGhost

แก้ไขเพื่อนขอโทษ
Avinash Raj

การแก้ไขของคุณไม่ได้ชี้แจงตัวอย่างของคุณอย่างแท้จริง โปรดดูความคิดเห็นล่าสุดของฉัน
HalosGhost

ลบเครื่องหมายจุลภาคทั้งหมดภายในอัญประกาศคู่และอัญประกาศก็ต่อเมื่อเครื่องหมายคำพูดมีตัวเลข
Avinash Raj

คำตอบ:


7

สิ่งนี้ (ดัดแปลงจากที่นี่ ) ควรทำในสิ่งที่คุณต้องการแม้ว่า @ rici's Perl one นั้นง่ายกว่ามาก:

$ sed -r ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;ta; s/""/","/g; 
          s/"([0-9]*)",?/\1,/g ' file
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454,
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

คำอธิบาย

  • :a: aกำหนดฉลากที่เรียกว่า
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/ : อันนี้ต้องถูกทำลายลง
    • ครั้งแรกของทั้งหมดโดยใช้โครงสร้างนี้(foo(bar)), \1จะเป็นfoobarและจะเป็น\2bar
    • "[0-9,]*",?: ตรงกับ 0 หรือมากกว่า0-9หรือ,ตามด้วย 0 หรือ ,1
    • ("[0-9,]*",?)* : ตรงกับ 0 หรือมากกว่าข้างต้น
    • "[0-9,]*: ตรงกับ 0 หรือมากกว่า0-9หรือ,ว่ามาทางขวาหลังจากที่"
  • ta;: กลับไปที่ป้ายกำกับaและเรียกใช้อีกครั้งหากการทดแทนสำเร็จ
  • s/""/","/g;: โพสต์การประมวลผล แทนที่ด้วย""","
  • s/"([0-9]*)",?/\1,/g : ลบเครื่องหมายคำพูดรอบ ๆ ตัวเลข

นี่อาจเป็นเรื่องง่ายที่จะเข้าใจด้วยตัวอย่างอื่น:

$ echo '"1,2,3,4"' | sed -nr ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;p;ta;'
"1,2,34"
"1,234"
"1234"
"1234"

ดังนั้นในขณะที่คุณสามารถค้นหาหมายเลขที่อยู่หลังเครื่องหมายคำพูดและตามด้วยเครื่องหมายจุลภาคและหมายเลขอื่นให้เข้าร่วมตัวเลขทั้งสองเข้าด้วยกันและทำซ้ำกระบวนการจนกว่าจะเป็นไปไม่ได้อีกต่อไป

ถึงตอนนี้ฉันเชื่อว่ามันมีประโยชน์ที่จะพูดถึงข้อความinfo sedที่ปรากฏในส่วนที่อธิบายถึงฟังก์ชั่นขั้นสูงเช่นฉลากที่ใช้ข้างต้น (ขอบคุณสำหรับการค้นหาว่า @Braiam):

ในกรณีส่วนใหญ่การใช้คำสั่งเหล่านี้บ่งชี้ว่าคุณน่าจะดีกว่าการเขียนโปรแกรมในบางสิ่งเช่น `awk 'หรือ Perl


10

ถ้า Perl เป็นปกตินี่คือวิธีสั้น ๆ (และอาจเร็วถ้าไม่จำเป็นต้องง่าย :)):

perl -pe 's:"(\d[\d,]+)":$1=~y/,//dr:eg' file

การeตั้งค่าสถานะไปยังs:::โอเปอเรเตอร์ (ซึ่งเป็นอีกวิธีหนึ่งในการเขียนs///) ทำให้การแทนที่ถูกใช้เป็นนิพจน์ซึ่งประเมินผลทุกครั้ง นิพจน์นั้นใช้การ$1ดักจับจาก regex (ซึ่งไม่มีเครื่องหมายคำพูดอยู่) และแปล ( y///ซึ่งสามารถเขียนเป็นtr///) ได้ด้วยการลบ ( /d) เครื่องหมายจุลภาคทั้งหมด rธงyเป็นสิ่งที่จำเป็นเพื่อให้ได้รับความคุ้มค่าที่จะเป็นสตริงแปลแทนการนับการแปล

สำหรับผู้ที่รู้สึกเบื่อโดย perl นี่คือหลามเทียบเท่า Python ไม่ได้เป็นเครื่องมือซับเดียวของเชลล์ แต่บางครั้งมันสามารถเปลี่ยนเป็นความร่วมมือได้ ข้อความต่อไปนี้สามารถเขียนเป็นหนึ่งบรรทัด (ซึ่งแตกต่างจากforลูปซึ่งไม่สามารถเป็นได้) แต่การเลื่อนแนวนอนทำให้ไม่สามารถอ่านได้ (ยิ่งมากกว่า):

python -c '
import re;
import sys;
r=re.compile("\"(\d+(,\d+)*)\"");
all(not sys.stdout.write(r.sub(lambda m:m.group(1).replace(",",""),l))
    for l in sys.stdin)
' < file

@rici: หนึ่งที่ดี! และใช้y///แทนการtr///ช่วยเราเพิ่มอีกหนึ่งตัวอักษร
cuonglm

6

สำหรับข้อมูล CSV ฉันจะใช้ภาษากับตัวแยกวิเคราะห์ CSV จริง ตัวอย่างเช่นกับ Ruby:

ruby -rcsv -pe '
  row = CSV::parse_line($_).map {|e| e.delete!(",") if e =~ /^[\d,]+$/; e} 
  $_  = CSV::generate_line(row)
' <<END
56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"
END
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

0

blockquote

สวัสดีนี่คือรหัสPythonเพื่อแทนที่เครื่องหมายจุลภาคด้วยเครื่องหมายอัญประกาศคู่เครื่องหมายจุลภาคจะถูกแทนที่ด้วยอักขระไพพ์ (|)

รหัส Python นี้เป็นการแทนที่เครื่องหมายจุลภาคที่อยู่ในเครื่องหมายคำพูดคู่

เช่น: x, y, z, 1,2, "r, e, t, y", h, 8,5,6

หากแทนที่ด้วย Pipe x, y, z, 1,2, "r | e | t | y", h, 8,5,6

หากแทนที่ด้วย null x, y, z, 1,2, "rety", h, 8,5,6

writingFile = open('FileToWrite', 'w')
with open('FileToRead') as f:

    while True:

        c = f.read(1)
        if not c:
            print ("End of file")
            break
        print ("Read a character:", c)


        if c=='"':
            writingFile.write(c) 
            c = f.read(1)
            while c != '"':
                if c== ',':
                    c= '|'
                writingFile.write(c)
                c = f.read(1)


        writingFile.write(c)


writingFile.close()

ต้องการคำอธิบายเล็กน้อย
Mongrel

รหัสไพ ธ อนนี้ใช้เพื่อแทนที่สิ่งต่าง ๆ ในเครื่องหมายคำพูดคู่
Vijay Kumar Akarapu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.