Có thể với Gedit hoặc dòng lệnh để sửa đổi mọi dòng thứ tư của tệp văn bản?


11

Tôi đang cố gắng chuyển đổi một tệp văn bản thành một bảng tính tách tab. Tệp văn bản của tôi là một cái gì đó như thế này:

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

Với các chức năng tìm kiếm và thay thế tiêu chuẩn trong Gedit hoặc LibreOffice, thật dễ dàng để thay thế cuối dòng bằng một tab. Nhưng nếu tôi chỉ trao đổi trả lại vận chuyển cho các tab, tôi sẽ nhận được điều này:

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

Nhưng những gì tôi cần làm là làm cho nó trông như thế này:

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

Vì vậy, tôi có thể trao đổi mọi đầu của ký tự dòng cho một tab ngoại trừ mỗi dòng thứ tư không?

Tôi không biết liệu loại lặp có điều kiện đó có thể được thực hiện bằng các biểu thức chính quy trong một chương trình như Gedit hoặc LibreOffice không, vì vậy có lẽ đây cần phải là một loại chức năng dòng lệnh? Tôi thậm chí không rõ công cụ tốt nhất để bắt đầu là gì.


Cập nhật:

Tôi đã thử các lệnh sau:

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

Nhưng khi tôi cố gắng mở tsvtệp kết quả trong LibreOffice, các cột không hoàn toàn đúng. Tôi không chắc điều này có nghĩa là tôi không thực hiện đúng các lệnh trên hay nếu tôi đang làm gì đó sai trong chức năng nhập LibreScript:

TSV khai trương tại Calc

Chỉ để tham khảo, kết quả mong muốn sẽ như thế này:

Cột thích hợp

Câu trả lời:


16

Bạn có thể sử dụng trình soạn thảo dòng lệnh nhưsed

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

hoặc, theo lập trình hơn, bằng cách thêm các ký tự tiếp tục dòng dấu gạch chéo ngược vào mỗi dòng bạn muốn tham gia bằng n skip mtoán tử địa chỉ của GNU sed và theo dõi nó bằng một lớp lót cổ điển để nối các dòng tiếp tục:

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

Xem ví dụ Giải thích về One-Liners :

  1. Nối một dòng vào dòng tiếp theo nếu nó kết thúc bằng dấu gạch chéo ngược "\".

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

Tuy nhiên, IMHO có thể dễ dàng hơn với một trong những tiện ích xử lý văn bản tiêu chuẩn khác, vd

paste - - - - < file > file.tsv

(số lượng -sẽ tương ứng với số lượng cột) hoặc

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

(bạn có thể bỏ qua -s$'\tnếu bạn không nhớ đầu ra được phân tách bằng nhiều tab).


Hành vi nhập lại kỳ lạ mà bạn đang quan sát gần như chắc chắn vì tệp gốc có kết thúc dòng CRLF kiểu Windows. Nếu bạn cần làm việc với các tệp từ Windows, thì bạn có thể cuộn chuyển đổi thành lệnh theo nhiều cách khác nhau, vd

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

hoặc là

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

Cái trước sẽ loại bỏ TẤT CẢ vận chuyển trở lại trong khi cái sau sẽ giữ CR ở cuối mỗi dòng mới (có thể là thứ bạn muốn nếu người dùng cuối dự định ở trên Windows).


1
Một lưu ý về kết thúc dòng kiểu Windows: các công cụ tiêu chuẩn để chuyển đổi giữa chúng và kiểu Unix là dos2unixunix2dos.
David Foerster

13

Bạn có thể sử dụng xargsđể luôn nhóm bốn dòng thành một, mỗi dòng cách nhau:

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

-d '\n'đặt dấu phân cách đầu vào thành một ký tự dòng mới, nếu không nó cũng sẽ phá vỡ khoảng trắng. Nếu bạn chỉ có một từ trên mỗi dòng đầu vào, bạn thậm chí có thể bỏ qua từ này.
-n4đặt số đối số (số lượng mục đầu vào trên mỗi dòng đầu ra) thành 4.

Đầu ra:

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

Hoặc nếu bạn muốn các tab làm dấu phân cách thay vì khoảng trắng, bạn có thể thay thế chúng sau đó. Tuy nhiên, nếu bạn có khoảng trắng trong dòng đầu vào của mình, chúng cũng sẽ được thay thế:

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

Đầu ra (xem tùy thuộc vào độ rộng tab của trình duyệt / thiết bị đầu cuối):

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

Phương pháp này có lợi ích là nó hoạt động hợp lý ngay cả khi tổng số dòng đầu vào không phải là bội số của bốn.
Eliah Kagan

3

Bạn cũng có thể sử dụng:

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

Hai biến tích hợp awk là:

  • ORS: O utput R ecord S eparator (default = newline). Nó được thêm vào cuối mỗi lệnh in.
  • NR: N số của R ow awk hiện tại đang xử lý.

Lệnh này sẽ, cho mỗi dòng, hiển thị nội dung của cột đầu tiên (và chỉ ở đây). Sau đó, nó chọn thêm một dòng mới hoặc một tab bằng cách kiểm tra phần còn lại của phép chia cho NR4.


3

Một awkcách tiếp cận ngắn nhất khác :

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

Đây printf chỉ một cột tiếp theo tiếp theo và tiếp theo và ... và một Tab \tnhân vật sau mỗi lần nhưng sẽ printf một \nnhân vật ewline khi N màu nâu đen của R ecord là yếu tố của 4 (nơi NR%4sẽ trở về 0 (false) đó là những gì ternary điều hành condition(s)?when-true:when-falseđang làm.)


3

Giải pháp của tôi cho vấn đề này là sử dụng kết hợp sedsed. Đầu tiên, bạn có thể đánh dấu mỗi dòng thứ tư bằng một số ký tự đặc biệt, ví dụ >, bằng cách sử dụng giải pháp này:

Trong trường hợp này, bạn muốn bắt đầu từ dòng 5 và đánh dấu mỗi dòng thứ 4 sau nó. Trong GNU sedcó thể được cung cấp như một địa chỉ 5~4. Bạn có thể sử dụng lệnh này:

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

Sau đó, bạn cần xóa các dòng mới, có thể được thực hiện với một sedvòng lặp:

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

Có nhiều cách dễ dàng hơn để chuyển đổi dòng mới sang một số ký tự khác, ví dụ như tr:

tr '\n' ' ' < file2 > file3

Dù bằng cách nào, kết hợp cả hai cho

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

( sedphiên bản để lại một dòng mới, trong khi trphiên bản thì không)

Sau đó, bạn chỉ cần chuyển đổi các ký tự đặc biệt bạn đã chèn sang dòng mới; xem ví dụ Chuyển đổi tệp được phân định bằng tab để sử dụng dòng mới . Trong trường hợp này, thay đổi >thành dòng mới:

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

Các ylệnh thực hiện chức năng giống như tr, chuyển một ký tự vào một, nhưng bạn có thể sử dụng các slệnh ở đây tốt như nhau. Với s, bạn cần gphải hoạt động trên mỗi trận đấu trong dòng ( sed 's/>/\n/g').

Thay vì tạo hai tệp trung gian, bạn có thể sử dụng đường ống:

$ 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

Nếu dấu cách là một vấn đề, bạn có thể thêm một lệnh khác để loại bỏ chúng:

| sed 's/ $//'

2

Vì mục đích "hoàn thiện" đây là một giải pháp bash thuần túy:

#!/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

Cũng hoạt động với các khoảng trắng, giả sử IFSđược đặt đúng (theo mặc định, AFAIK). Hơn nữa, tôi nghĩ rằng đây thậm chí có thể là một tập lệnh shell di động và hoạt động với bất kỳ trình bao tương thích POSIX nào.


1
Nói chung, điều này không khả chuyển đối với các vỏ tương thích POSIX, vì $' 'hình thức trích dẫn không được POSIX yêu cầu. Ví dụ: trong dash(cung cấp shtheo mặc định trên Ubuntu), printf '%s\n' $'a\tb'chỉ chạy các đầu ra $a\tb. Điều đó không có nghĩa là điều này không hữu ích mặc dù; nó không hoạt động trong bash. Tuy nhiên, như với một số giải pháp khác mà mọi người đã đăng, nó tạo ra đầu ra không đầy đủ nếu số lượng dòng đầu vào không phải là bội số của bốn. Ngoài ra, tôi khuyên bạn nên sử dụng read -r, vì không có lý do gì để nghĩ rằng việc mở rộng dấu gạch chéo ngược trong tệp đầu vào là mong muốn ở đây.
Eliah Kagan

Bạn chỉ có thể làmprintf '%s\t%s\t%s\t%s\n' "$one" "$two" "$three" "$four"
terdon

2

Một macro vim (được ghi bằng q) có thể áp dụng thao tác của bạn, sau đó bỏ qua ba dòng. Sau đó, bạn chỉ cần chạy macro n lần.

ví dụ:

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

2

Vì bạn đã yêu cầu một giải pháp Gedit, một cái gì đó như thế này sẽ hoạt động:

Tìm thấy:

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

Thay thế bằng:

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

Hãy chắc chắn rằng hộp kiểm cho các biểu thức thông thường được đánh dấu.

Làm thế nào nó hoạt động:

Bước đầu tiên là tìm một loạt các ký tự từ, với \ w + và nắm bắt các kết quả trong biến \ 1 bằng cách gói các dấu ngoặc đơn quanh biểu thức:

(\w+)

Tiếp theo, chúng tôi tìm kiếm một loạt các ký tự kết thúc dòng, \ r và \ n hoặc CR và LF. Vì các tệp được định dạng của Windows sử dụng cả hai, chúng tôi tạo một lớp ký tự bằng cách gói hai ký tự này trong ngoặc vuông. Điểm cộng làm cho nó tìm kiếm một hoặc nhiều ký tự:

[\r\n]+

Cuối cùng, chúng tôi lặp lại 3 lần nữa, lưu trữ từng từ tiếp theo trong các biến \ 2, \ 3 và \ 4. Điều này làm cho thay thế của chúng tôi với biểu thức đơn giản. Chúng tôi chỉ cần đặt các ký tự tab, \ t và một ký tự dòng mới, \ n, ở những vị trí thích hợp cho định dạng bạn cần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.