เป็นวิธีที่ดีในการกรองไฟล์ข้อความเพื่อลบบรรทัดว่างอะไร


11

ฉันมีไฟล์. csv (สำหรับ mac) ที่มีบรรทัดว่างมากมายเช่น:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"

ซึ่งฉันต้องการแปลงเป็น:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum  lorem ipsum ","2","3","4"

ฉันรู้ว่าต้องมีสายการบินเดียว แต่ฉันไม่รู้ว่าน่าอายหรือไม่ดี เคล็ดลับใด ๆ ที่ชื่นชมอย่างมาก!


1
ตามตัวอย่างคุณต้องการลบตัวแบ่งบรรทัดที่ฝังอยู่ออกจากฟิลด์จริง ๆ ถูกต้องหรือไม่ กล่าวอีกนัยหนึ่งมี 6 สายอินพุตและควรเป็น 2 บรรทัดเอาท์พุท?
จัดการ

ใช่นั่นคือสิ่งที่ฉันพยายามกำจัด: ฝังตัวขึ้นบรรทัดใหม่ภายในสตริงที่ยกมา
pitosalas

ดังนั้นสิ่งที่คุณต้องการคือสิ่งที่ลบบรรทัดใหม่ภายในเครื่องหมายคำพูด มันจะซับซ้อนกว่านี้นิดหน่อยเพราะคุณต้องใช้ regex หลาย ๆ อัน
tongpu

คำตอบ:


11

คุณสามารถใช้-vโหมดgrep's (จับคู่กลับด้าน) เพื่อทำสิ่งนี้:

grep -v '^$' old-file.csv > new-file.csv

โปรดทราบว่าไฟล์เหล่านั้นต้องเป็นไฟล์อื่นเนื่องจากเชลล์เปลี่ยนเส้นทางทำงานอย่างไร ไฟล์เอาต์พุตถูกเปิด (และว่างเปล่า) ก่อนที่จะอ่านไฟล์อินพุต หากคุณมีมากขึ้น (ไม่ใช่โดยค่าเริ่มต้นใน Mac OS X) คุณสามารถใช้spongeเพื่อแก้ไขปัญหานี้:

grep -v '^$' file.csv | sponge file.csv

แต่แน่นอนว่าคุณมีเวลาที่ยากลำบากในการกลับไปหาสิ่งที่ผิดพลาด

หากคุณ "บรรทัดว่าง" จริงๆแล้วอาจมีช่องว่าง (ดูเหมือนว่าพวกเขาทำ) คุณสามารถใช้สิ่งนี้แทน:

egrep -v '^[[:space:]]*$' old-file.csv > new-file.csv

ที่จะละเว้นบรรทัดว่างเปล่ารวมถึงบรรทัดที่มีช่องว่างเท่านั้น แน่นอนคุณสามารถทำการspongeแปลงเดียวกันกับมัน


ขอบคุณ .... ไม่ได้ลบบรรทัดว่างเปล่า ... บางที ^ $ อาจไม่ตรงกันใช่ไหม แต่บรรทัดว่างเปล่าที่ดีที่สุดของความรู้ของฉัน จำไว้ว่านี่คือ cdv ที่สร้างขึ้นโดย excel ใน mac ... มันพูดอะไรอีกหรือเปล่า? (ไม่ต้องวิ่งหนีไปกรีดร้องเพราะผมกล่าว Excel :)
pitosalas

@pitosalas พวกเขาอาจไม่ว่างเปล่า ลองเปลี่ยนเป็นegrep -v '^[[:space:]]*$'... note grep -> egrep และรูปแบบแปลก ๆ ใหม่
Derobert

ไม่ทำงาน ที่ถูกลบพวงของราคาคู่และทำให้เป็นระเบียบ ...
pitosalas

@pitosalas ฉันไม่แน่ใจว่าจะลบเครื่องหมายคำพูดคู่ได้อย่างไร มันควรจะสามารถลบช่องว่างเท่านั้น และแน่นอนว่าเป็นสิ่งที่มันไม่เมื่อผมทดสอบบนข้อมูลตัวอย่างที่คุณโพสต์ ...
derobert

@pitosalas คุณสามารถตรวจสอบว่าหนึ่งในคำสั่งเหล่านี้คายบางสิ่งบางอย่างที่ดูสมเหตุสมผล (เมื่อเทียบกับซึ่งพูดพล่อยๆ): iconv -f utf16le file.csv | headหรือiconv -f utf16be file.csv | head
Derobert

8

grep .ตัวเลือกที่ง่ายที่สุดคือเพียง ที่นี่จุดหมายถึง "จับคู่อะไร" ดังนั้นถ้าบรรทัดว่างเปล่ามันจะไม่ตรงกัน อื่นมันพิมพ์เส้นทั้งหมดตามที่เป็น


6

ในการลบเส้นที่ว่างเปล่าในสถานที่ที่มี ksh93:

sed '/./!d' file 1<>; file

<>;ผู้ประกอบการเปลี่ยนเส้นทางเป็นเฉพาะกับ ksh93 และเป็นเช่นเดียวกับมาตรฐาน<>ผู้ประกอบการยกเว้น ksh ที่ตัดทอนไฟล์หลังจากคำสั่งมีการยกเลิก

sed '/./!d'เป็นวิธีที่ซับซ้อนในการเขียนgrep .แต่น่าเสียดายที่ GNU grep บ่นอย่างน้อยถ้า stdout ชี้ไปที่ไฟล์เดียวกันกับ stdin คุณจะบอกว่ามีใครสามารถเขียน:

grep . file | cat 1<>; file

แต่น่าเสียดายที่มีข้อบกพร่องใน ksh93 (อย่างน้อยรุ่นของฉัน (93u +)) ซึ่งดูเหมือนว่าไฟล์จะถูกตัดให้มีความยาวเป็นศูนย์ในกรณีนี้

grep . file | { cat; } 1<>; file

ดูเหมือนว่าจะแก้ไขข้อผิดพลาดนั้น แต่ตอนนี้มันซับซ้อนกว่าคำสั่ง sed


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

@Caleb มันทำให้เกิดคำถามที่ไม่ชัดเจนดังนั้นทุกคำตอบของทุกคนจึงมีความหมายที่แตกต่างกัน สำหรับแต่ละคำตอบฉันพยายามพูดว่าคำถามใดที่พยายามตอบ
Stéphane Chazelas

เพียงแค่ FYI: พยายามawk '/./' file 1<>; fileซึ่งทำงานได้ สำหรับฉันมันชัดเจนยิ่งกว่าsed '/./!d'
grebneke

5

นี่คือPerlหนึ่งซับสำหรับมัน:

perl -pi -e 's/^\s*\n//' yourfile

แก้ไข: รหัสที่ปรับปรุงใหม่ตามความคิดเห็นของ ruakh ด้านล่าง


1
หรือperl -ni -e '/./ and print' yourfile
เบิร์ต

1
@peterph $เป็นจุดยึด (เช่นความกว้างศูนย์) ดังนั้นจึงไม่รวมบรรทัดใหม่ สำหรับพื้นที่ฟุ่มเฟือยมันเป็นเหตุผลที่ฉันเพิ่ม/xฉันไม่ต้องการPerlลอง interpolating `$ \ 'ลงใน regex
Joseph R.

1
คุณไม่จำเป็นต้องให้ที่คุณมี$ \n(หรืออีกวิธีหนึ่ง - คุณไม่จำเป็นต้อง\nระบุว่าคุณมี\s*และ$แต่ฉันคิดว่าs/^\s*\n//มันชัดเจนว่าขึ้นบรรทัดใหม่จะถูกลบ) คุณยังไม่จำเป็นต้อง/m; มันไม่มีผลกับคำสั่งนี้ และเมื่อคุณได้รับการกำจัดของและพื้นที่ที่คุณจะไม่จำเป็นต้อง$ /x
ruakh

1
@JosephR .: \nตัวเองสามารถลบได้ สิ่งที่คุณไม่สามารถทำได้คือเอาทั้ง$ และ \nดังนั้นs/^\s*//จะมีปัญหาที่คุณอธิบาย แต่s/^\s*$//จะดีเพราะการและ\s* $(คุณเห็นสิ่งที่ฉันหมายถึงอะไร?)
ruakh

1
@JosephR .: สิ่งที่เกิดขึ้นคือ$ สามารถตรงกับก่อนที่จะขึ้นบรรทัดใหม่ (ให้ว่าทั้ง/mธงถูกเปิดใช้งานหรือการขึ้นบรรทัดใหม่เป็นตัวละครสุดท้ายของสตริงหรือทั้งสอง) แต่ก็สามารถยังตรงกับจุดสิ้นสุดของสตริง ตัวอย่างเช่น"abc" =~ m/^abc$/เป็นจริง ในกรณีของ\s*$ความ\s*โลภมากพอที่จะกินบรรทัดใหม่แล้ว$ตรงกับจุดสิ้นสุดของสายอักขระ ( แต่ผมคิดว่าs/^\s*\n//เป็นที่ชัดเจนอยู่แล้วดังนั้นคำตอบของคุณเป็นเพียงแค่ปรับเป็นอยู่ในปัจจุบัน.)
ruakh

5

จากการชี้แจงในความคิดเห็นต่อคำถามของคุณมีดังนี้:

awk -v RS= -v ORS= 1

อาจทำสิ่งที่คุณต้องการ

ตัวคั่นเรคคอร์ดที่ว่างเปล่าเป็นกรณีพิเศษที่บอกawkว่าเร็กคอร์ดนั้นเป็นย่อหน้า (คั่นด้วยลำดับของบรรทัดที่ว่าง) การตั้งค่าตัวคั่นเร็กคอร์ดเอาต์พุตเป็นสตริงว่างเช่นกันหมายความว่าเนื้อหาของย่อหน้าเหล่านั้น (ไม่มีตัวคั่น) จะถูกต่อกัน 1เป็นเพียงเงื่อนไขที่แท้จริงในการพิมพ์ทุกระเบียน

อย่างไรก็ตามนั่นจะเป็นการตัดบรรทัดใหม่ที่ตามมาดังนั้นคุณสามารถทำได้:

awk -v RS= -v ORS= '1;END{if (NR) printf "\n"}'

3

ฉันรู้ว่ามันจะง่ายกว่านี้ถ้าฉันให้ไฟล์ แต่น่าเสียดายที่มันมีข้อมูลลับที่ฉันไม่สามารถแชร์ได้ ในขณะที่ฉันเขียนสคริปต์ทับทิมที่ดูเหมือนจะหลอกลวง:

require 'csv'
c = CSV.open("outfile1.csv", "w")
CSV.foreach("data.csv", :encoding => 'windows-1251:utf-8') do |row|
  row = row.map { |a| a.class == String ? a.gsub(/\r/, '') : a}
  c << row
end
c.close

ขอบคุณทุกคนที่ช่วย!


2
awk '
    length == 0 {next} 
    /^[^"]/ && /"$/ {print; next} 
    {printf("%s", $0)}
' filename

ผลิต

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"

2

ผมพบว่าความคิดสำหรับการแก้ปัญหาเป็นไปได้ในStackOverflow

sed -i ':a;N;$!ba;s/[^"]\n\s*\n/ /g' file.csv

คุณควรสำรองไฟล์ csv ของคุณก่อนทดสอบ แต่อย่างน้อยสำหรับตัวอย่างที่คุณให้มามันทำงานได้อย่างไม่มีที่ติ

คำอธิบายที่ดีเกี่ยวกับการทำงานด้านในของการแสดงออกนี้มีให้ที่คำตอบฉันเพิ่งแก้ไขเพื่อค้นหาบรรทัดที่ไม่ได้ลงท้ายด้วย"( [^"]\n)


1

หากคุณต้องการลบอักขระบรรทัดใหม่ที่มีอยู่ในสตริงที่ยกมาจากการตอบกลับของคุณเองคุณสามารถทำได้:

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse'

นอกจากนี้คุณยังสามารถใช้การใช้งานของ Perl -iธงไปที่การแก้ไขไฟล์ที่อยู่ในสถานที่

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse' file1 file2...

หรือด้วย GNU awk:

 awk -v RS=\" 'NR%2==0 {gsub("\n","")}; {printf "%s", $0 RT}'

หรือ:

 awk -vRS=\" '1-NR%2{gsub("\n","")}{ORS=RT}1'

(หากคุณกำลังแข่งขันเพื่อช่วงเวลาที่สั้นที่สุด)

โปรดทราบว่าผู้ที่คิดว่ามีไม่หนีตัวอักษรราคาคู่ในการป้อนข้อมูล


0

ดูเหมือนว่าคุณต้องการมากกว่าลบบรรทัดว่าง แต่ลบทุกบรรทัดของอักขระขึ้นบรรทัดใหม่ 2 ตัวขึ้นไป

ซึ่งคุณสามารถทำกับ perl:

perl -0777 -pe 's/\n{2,}//gs' file

นอกจากนี้คุณยังสามารถใช้การใช้งานของ Perl -iธงไปที่การแก้ไขไฟล์ที่อยู่ในสถานที่

perl -0777 -pi -e 's/\n{2,}//gs' file1 file2...

0

มีวิธีที่สั้นกว่าเดิมในการลบบรรทัดว่างในAWK:

awk 'NF' file

แต่เพื่อให้ได้ผลลัพธ์ที่คุณต้องการสิ่งที่จำเป็นทั้งหมดคือซับง่ายๆ:

awk 'NF {printf("%s ", $0); i++;} !(i % 2) {printf("\n");}' file

คำอธิบาย

ในAWKบรรทัดว่างหมายถึงแถว / ระเบียนไม่มีฟิลด์กล่าวคือNFตัวแปร (จำนวนฟิลด์) เป็นศูนย์ ซับหนึ่งด้านบนจะทำงานเมื่อNF > 0พิมพ์ทุกบรรทัด แต่บรรทัดที่ว่างเปล่า

i++เป็นไม่ว่างเปล่าเคาน์เตอร์สาย

!(i % 2)ถูกนำมาใช้ในการสั่งซื้อที่จะพิมพ์สองสายไม่ว่างเปล่าติดต่อกันในลักษณะของการส่งออกที่ต้องการนั่นคือทุกครั้งหลาย 2 พบที่moduloงบ!(i % 2)อัตราผลตอบแทน 1 สิ่งที่ยุติการเรียงต่อกันของทั้งสองสายที่ไม่ว่างเปล่า


ความผิดฉันเอง! ขอโทษ ฉันไม่ได้อ่านคำถามทั้งหมดและผลลัพธ์ที่ต้องการ การตอบกลับได้รับการแก้ไขแล้ว ขอบคุณ :-)
Marcelo Augusto

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