เป็นไปได้ด้วย Gedit หรือบรรทัดคำสั่งเพื่อแก้ไขทุกบรรทัดที่สี่ของไฟล์ข้อความ?


11

ฉันพยายามแปลงไฟล์ข้อความเป็นสเปรดชีตที่คั่นด้วยแท็บ ไฟล์ข้อความของฉันเป็นดังนี้:

Dog
Cat
Fish
Lizard
Wolf
Lion
Shark
Gecko
Coyote
Puma
Eel
Iguana

ด้วยการค้นหาและแทนที่ฟังก์ชั่นมาตรฐานใน Gedit หรือ LibreOffice มันง่ายที่จะแทนที่ส่วนท้ายของบรรทัดด้วยแท็บ แต่ถ้าฉันเพียงแค่สลับ carriage return สำหรับแท็บฉันจะได้รับสิ่งนี้:

Dog   Cat   Fish   Lizard   Wolf   Lion   Shark   Gecko   Coyote   Puma   Eel   Iguana

แต่สิ่งที่ฉันต้องทำคือให้มันเป็นแบบนี้:

Dog   Cat   Fish   Lizard
Wolf   Lion   Shark   Gecko  
Coyote   Puma   Eel   Iguana

ดังนั้นฉันสามารถสลับอักขระปลายบรรทัดสำหรับแท็บได้ยกเว้นทุกบรรทัดที่สี่หรือไม่

ฉันไม่ทราบว่าการวนซ้ำแบบมีเงื่อนไขสามารถทำได้ด้วยนิพจน์ทั่วไปภายในโปรแกรมเช่น Gedit หรือ LibreOffice ดังนั้นอาจจำเป็นต้องมีฟังก์ชันบรรทัดคำสั่งบางอย่างหรือไม่ ฉันยังไม่ชัดเจนว่าเครื่องมือที่ดีที่สุดในการเริ่มต้นคืออะไร


ปรับปรุง:

ฉันลองคำสั่งต่อไปนี้:

sed 'N;N;N;s/\n/\t/g' file > file.tsv

paste - - - - < file > file.tsv

pr -aT -s$'\t' -4 file > file.tsv

xargs -d '\n' -n4 < inputfile.txt

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

เปิด TSV ใน Calc

เพื่อการอ้างอิงผลลัพธ์ที่ต้องการควรมีลักษณะเช่นนี้:

คอลัมน์ที่เหมาะสม

คำตอบ:


16

คุณสามารถใช้เครื่องมือแก้ไขบรรทัดคำสั่งเช่นsed

sed 'N;N;N;s/\n/\t/g' file > file.tsv

หรือมากกว่านั้นโดยทางโปรแกรมโดยการเพิ่มอักขระต่อเนื่องของแบ็กสแลชของบรรทัดในแต่ละบรรทัดที่คุณต้องการเข้าร่วมโดยใช้n skip mโอเปอเรเตอร์ที่อยู่ของ GNU sed และตามด้วยไลน์เดียวแบบคลาสสิกสำหรับการเข้าร่วมไลน์ต่อเนื่อง

sed '0~4! s/$/\t\\/' file | sed -e :a -e '/\\$/N; s/\\\n//; ta'

ดูตัวอย่างSed One-Liners อธิบาย :

  1. ต่อท้ายบรรทัดหากบรรทัดนั้นลงท้ายด้วยแบ็กสแลช "\"

    sed -e :a -e '/\\$/N; s/\\\n//; ta'
    

อย่างไรก็ตาม IMHO จะง่ายขึ้นด้วยยูทิลิตี้การประมวลผลข้อความมาตรฐานอื่น ๆ เช่น

paste - - - - < file > file.tsv

(จำนวน-จะสอดคล้องกับจำนวนคอลัมน์) หรือ

pr -aT -s$'\t' -4 file > file.tsv

(คุณสามารถละเว้น-s$'\tถ้าคุณไม่คำนึงถึงผลลัพธ์ที่จะคั่นด้วยแท็บหลายแท็บ)


พฤติกรรมการนำเข้าที่แปลกที่คุณกำลังสังเกตอยู่นั้นเกือบจะแน่นอนเพราะไฟล์ต้นฉบับมีการสิ้นสุดบรรทัด CRLF สไตล์ Windows หากคุณต้องการทำงานกับไฟล์จาก Windows คุณสามารถย้อนการแปลงเป็นคำสั่งได้หลายวิธีเช่น

tr -d '\r' < file.csv | paste - - - -

หรือ

sed 'N;N;N;s/\r\n/\t/g' file.csv

อดีตจะลบการขึ้นบรรทัดใหม่ทั้งหมดในขณะที่อันหลังจะเก็บ CR ไว้ที่จุดสิ้นสุดของบรรทัดใหม่แต่ละบรรทัด (ซึ่งอาจเป็นสิ่งที่คุณต้องการหากผู้ใช้ปลายทางตั้งใจอยู่บน Windows)


1
ทราบเกี่ยวกับ Windows แบบจบบรรทัด: เครื่องมือมาตรฐานในการแปลงระหว่างพวกเขาและ Unix สไตล์และdos2unix unix2dos
David Foerster

13

คุณสามารถใช้xargsเพื่อจัดกลุ่มสี่บรรทัดเป็นหนึ่งเสมอคั่นด้วยช่องว่างเดียวแต่ละ:

xargs -d '\n' -n4 < inputfile.txt

-d '\n'ตั้งค่าตัวคั่นอินพุตเป็นอักขระขึ้นบรรทัดใหม่มิฉะนั้นจะทำให้ช่องว่างแตก หากคุณมีเพียงหนึ่งคำต่อบรรทัดอินพุตคุณสามารถเว้นไว้ได้
-n4ตั้งค่าหมายเลขอาร์กิวเมนต์ (จำนวนรายการอินพุตต่อบรรทัดเอาต์พุต) เป็น 4

เอาท์พุท:

Dog Cat Fish Lizard
Wolf Lion Shark Gecko
Coyote Puma Eel Iguana

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

xargs -d '\n' -n4 | tr ' ' '\t'

เอาต์พุต (ดูขึ้นอยู่กับความกว้างแท็บของเบราว์เซอร์ / เทอร์มินัล):

Dog Cat Fish    Lizard
Wolf    Lion    Shark   Gecko
Coyote  Puma    Eel Iguana

วิธีการนี้มีประโยชน์ที่จะทำงานอย่างมีเหตุผลแม้ว่าจำนวนบรรทัดทั้งหมดของการป้อนข้อมูลจะไม่คูณด้วยสี่
Eliah Kagan

3

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

awk -v ORS="" '{print $1; print NR%4==0?"\n":"\t"}' file > file.tsv 

ตัวแปรบิวด์อินสองตัว awk คือ:

  • ORS: O utput R eordator S eparator (ค่าเริ่มต้น = ขึ้นบรรทัดใหม่) มันถูกเพิ่มไว้ท้ายคำสั่งการพิมพ์แต่ละคำสั่ง
  • NR: Nสีน้ำตาลไหม้ของปัจจุบันRโอ๊ย awk คือการประมวลผล

คำสั่งนี้จะแสดงเนื้อหาของคอลัมน์แรก (และที่นี่เท่านั้น) สำหรับแต่ละบรรทัด จากนั้นจะเลือกเพิ่มบรรทัดใหม่หรือแท็บโดยทดสอบส่วนที่เหลือของการหารNRด้วย 4


3

อีกawkวิธีที่สั้นที่สุด:

awk '{printf $0 (NR%4?"\t":"\n")}' infile

นี้printfเพียงหนึ่งคอลัมน์ตามด้วยถัดไปและถัดไปและ ... และแท็บ\tตัวละครแต่ละหลัง แต่จะprintf\nตัวอักษร ewline เมื่อNสีน้ำตาลไหม้R ecord เป็นปัจจัย4 (ที่NR%4จะกลับ0 (เท็จ) ซึ่งเป็นสิ่งที่ผู้ประกอบการ Ternary condition(s)?when-true:when-falseกำลังทำ.)


3

ทางออกของฉันนี้จะใช้การรวมกันของและsed sedก่อนอื่นคุณสามารถทำเครื่องหมายทุกบรรทัดที่สี่ด้วยอักขระพิเศษตัวอย่างเช่น>ใช้โซลูชันนี้:

ในกรณีนี้คุณต้องการเริ่มจากบรรทัดที่ 5 และทำเครื่องหมายทุกบรรทัดที่ 4 หลังจากนั้น ใน GNU sedที่สามารถให้เป็นที่อยู่5~4ได้ คุณสามารถใช้คำสั่งนี้:

sed '5~4s/^/>/' file1 > file2

จากนั้นคุณต้องลบ newlines ซึ่งสามารถทำได้ด้วยการsedวนซ้ำ:

sed ':a;N;s/\n/ /;ba' file2 > file3

มีวิธีที่ง่ายกว่าในการแปลงบรรทัดใหม่เป็นอักขระอื่นเช่นtr:

tr '\n' ' ' < file2 > file3

ทั้งสองวิธีรวมสองให้

Dog   Cat   Fish   Lizard   >Wolf   Lion   Shark   Gecko   >Coyote   Puma   Eel   Iguana

( sedเวอร์ชันออกจากการขึ้นบรรทัดใหม่ขณะที่trเวอร์ชันไม่ได้ทำ)

หลังจากนั้นคุณต้องแปลงอักขระพิเศษที่คุณแทรกเป็นบรรทัดใหม่เท่านั้น ดูตัวอย่างแปลงไฟล์คั่นด้วยแท็บที่จะใช้การขึ้นบรรทัดใหม่ ในกรณีนี้เปลี่ยน>เป็นบรรทัดใหม่:

sed 'y/>/\n/' file3 > outfile

yคำสั่งดำเนินการฟังก์ชันเช่นเดียวกับtrการเปลี่ยนแปลงตัวละครตัวหนึ่งไปยังอีก แต่คุณสามารถใช้sคำสั่งที่นี่ดีพอ ๆ กัน ด้วยsคุณจะต้องgทำงานในแต่ละการแข่งขันในบรรทัด ( sed 's/>/\n/g')

แทนที่จะสร้างไฟล์กลางสองไฟล์คุณสามารถใช้ไพพ์:

$ sed '5~4s/^/>/' file | sed ':a;N;s/\n/ /;ba' | sed 'y/>/\n/'
Dog Cat Fish Lizard 
Wolf Lion Shark Gecko 
Coyote Puma Eel Iguana

หากช่องว่างต่อท้ายเป็นปัญหาคุณสามารถเพิ่มคำสั่งอื่นเพื่อลบออกได้:

| sed 's/ $//'

2

เพื่อประโยชน์ของ "ครบถ้วน" นี่เป็นวิธีทุบตีบริสุทธิ์:

#!/usr/bin/env bash

sep=$'\t'

while read one \
      && read two \
      && read three \
      && read four
do
  printf "%s\n" "$one$sep$two$sep$three$sep$four"
done

ใช้งานได้กับช่องว่างโดยสมมติว่าIFSมีการตั้งค่าอย่างเหมาะสม (ซึ่งควรเป็นค่าเริ่มต้น AFAIK) ยิ่งกว่านั้นฉันคิดว่านี่อาจเป็นสคริปต์เชลล์แบบพกพาและทำงานกับเชลล์ที่ใช้ POSIX ได้


1
นี่ไม่ใช่แบบพกพาไปยังเปลือกที่รองรับ POSIX โดยทั่วไปเนื่องจาก$' 'POSIX ไม่จำเป็นต้องใช้รูปแบบการอ้างอิง ยกตัวอย่างเช่นในdash(ซึ่งมีshค่าเริ่มต้นบน Ubuntu) วิ่งเพียงแค่เอาท์พุทprintf '%s\n' $'a\tb' $a\tbไม่ได้หมายความว่ามันจะไม่เป็นประโยชน์ มันทำงานในทุบตี อย่างไรก็ตามเช่นเดียวกับโซลูชันอื่น ๆ ที่ผู้คนโพสต์มันสร้างผลลัพธ์ไม่สมบูรณ์หากจำนวนบรรทัดอินพุตไม่ได้เป็นหลายเท่าของสี่ นอกจากนี้ฉันขอแนะนำให้ใช้read -rเนื่องจากไม่มีเหตุผลที่จะคิดว่าการขยายแบ็กสแลชในไฟล์อินพุตนั้นต้องการได้ที่นี่
Eliah Kagan

คุณสามารถทำได้printf '%s\t%s\t%s\t%s\n' "$one" "$two" "$three" "$four"
terdon

2

แมโคร vim (ที่บันทึกด้วย q) สามารถใช้การดำเนินการของคุณจากนั้นข้ามสามบรรทัด จากนั้นคุณเรียกใช้แมโครนั้น n ครั้ง

เช่น:

qq $ J i <TAB> <ESC> $ J i <TAB> <ESC> $ J i <TAB> <ESC> ^^ j qq 100 @q

2

เมื่อคุณขอวิธีแก้ปัญหาของ Gedit สิ่งนี้จะทำงานได้:

หา:

(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+

แทนที่ด้วย:

\1\t\2\t\3\t\4\n

ตรวจสอบให้แน่ใจว่ามีการทำเครื่องหมายในช่องสำหรับการแสดงออกปกติ

มันทำงานอย่างไร:

ขั้นตอนแรกคือการค้นหาชุดของอักขระคำด้วย \ w + และจับผลลัพธ์ในตัวแปร \ 1 โดยการใส่วงเล็บล้อมรอบนิพจน์:

(\w+)

ต่อไปเราจะค้นหาชุดของอักขระสิ้นสุดบรรทัด \ r และ \ n หรือ CR และ LF เนื่องจากไฟล์ที่จัดรูปแบบ Windows ใช้ทั้งคู่เราจึงสร้างคลาสตัวละครโดยใส่อักขระสองตัวนี้ไว้ในวงเล็บเหลี่ยม เครื่องหมายบวกทำให้ค้นหาอักขระหนึ่งตัวขึ้นไป:

[\r\n]+

ในที่สุดเราจะทำซ้ำ 3 ครั้งนี้โดยเก็บคำที่ตามมาในตัวแปร \ 2, \ 3 และ \ 4 สิ่งนี้ทำให้เราแทนที่ด้วยการแสดงออกง่าย เราเพียงแค่วางอักขระแท็บ \ t และอักขระบรรทัดใหม่ \ n ในตำแหน่งที่เหมาะสมสำหรับการจัดรูปแบบที่คุณต้องการ

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