Làm thế nào tôi có thể sửa chữa các dòng bị hỏng ở những nơi sai?


11

Tệp văn bản của tôi trông như thế này:

This is one
sentence that is broken.
However this is a good one.
And this
one is
somehow, broken into
many.

Tôi muốn xóa ký tự dòng mới cho bất kỳ dòng nào được theo sau bởi một dòng bắt đầu bằng một chữ cái viết thường.

Vì vậy, điều này nên là:

This is one sentence that is broken.
However this is a good one.
And this one is somehow, broken into many.

Tôi có thể làm cái này như thế nào?

Chỉnh sửa: Có một số câu trả lời thực sự tốt ở đây, nhưng tôi đã chọn chấp nhận câu trả lời đầu tiên có hiệu quả sớm nhất. Cảm ơn mọi người rất nhiều!


1
Mủ cao su? Vấn đề là bạn không thực sự nêu ra các quy tắc để phá vỡ câu đúng. Bạn có muốn đặt mọi thứ lên đến và bao gồm cả dấu câu cuối câu trên một dòng không? Nhưng nếu bạn có một câu dài và nó chạy ra khỏi rìa cửa sổ hiển thị của bạn thì sao?
jamesqf

1
Tôi tự hỏi những gì bạn đang thực sự cố gắng để giải quyết? Có lẽ bạn nên sử dụng định dạng markdown?
tự đại diện

@JeffSchaller Cảm ơn bạn đã nhắc nhở! Tôi đã bỏ lỡ bằng cách nào đó. :)

Câu trả lời:


7

thử

awk '$NF !~ /\.$/ { printf "%s ",$0 ; next ; } {print;}' file

Ở đâu

  • $NF !~ /\.$/ khớp dòng trong đó phần tử cuối cùng không kết thúc bằng dấu chấm,
  • { printf "%s ",$0 in dòng này với một không gian lưu trữ và không có nguồn cấp dữ liệu,
  • next ; } lấy dòng tiếp theo
  • {print;} và in nó.

Tôi chắc chắn sẽ có một sedlựa chọn.

Lưu ý: điều này sẽ hoạt động với dòng kết thúc bằng dấu chấm, tuy nhiên điều kiện trong câu bắt đầu bằng chữ in hoa sẽ không được hợp nhất. Xem câu trả lời của Stéphane Chazelas.


Nếu bạn thích thông minh (nhiều người không)awk 'ORS=$NF~/\.$/?"\n":" "'
dave_thndry_085

10

Với awk:

awk -v ORS= '{print (NR == 1 ? "" : /^[[:lower:]]/ ? " " : RS) $0}
             END {if (NR) print RS}'

Đó là, không nối phần phân tách bản ghi vào mỗi dòng (ORS trống). Nhưng hãy đặt trước một dấu tách bản ghi trước dòng hiện tại nếu không phải trên dòng đầu tiên và dòng hiện tại không bắt đầu bằng một chữ cái viết thường. Mặt khác, thay vào đó một ký tự khoảng trắng, ngoại trừ trên dòng đầu tiên.


Khi tôi chạy này, một số cặp từ được nối với nhau. Ví dụ And thisone issomehow, broken intomany.tôi không biết awknhưng dòng nên được nối với <space>ngoài RS? Hay là lỗi người dùng này?
Lớp B

@BLayer, phát hiện tốt, cảm ơn. Nên sửa ngay.
Stéphane Chazelas

Không vấn đề gì. Mặc dù người ta tự hỏi 11 upvote đến từ đâu. Phải thật tốt khi có người chỉ cho rằng bạn luôn đúng. ;)
Lớp B

4

Trong perl:

#!/usr/bin/perl -w
use strict;
my $input = join("", <>);
$input =~ s/\n([a-z])/ $1/g;
print $input;

Về mặt kỹ thuật, bạn muốn thay thế "dòng mới theo sau là chữ thường" bằng "khoảng trắng và chữ cái viết thường", đó là những gì cốt lõi của tập lệnh perl ở trên:

  1. Đọc trong đầu vào một chuỗi input.
  2. Cập nhật inputbiến là kết quả của hoạt động tìm kiếm & thay thế.
  3. In giá trị mới.

1
tốt một !! được dịch sang một lớp lót perl -0777 -pe 's/\n([a-z])/ $1/g'và có thể được thực hiện tương tự với GNU sed như sed -zE 's/\n([a-z])/ \1/g'(giả sử đầu vào không có ký tự null)
Sundeep

3
@Sundeep hoặc perl -Mopen=locale -0777 -pe 's/\n(?=[[:lower:]])/ /g'không giới hạn ở các chữ cái ASCII.
Stéphane Chazelas

4

Với sedbạn có thể sử dụng một N;P;Dchu trình (để luôn có hai dòng trong không gian mẫu và nếu ký tự đầu tiên sau dòng mới là chữ thường thì thay thế dòng mới bằng khoảng trắng ) và ttheo cách đó sau mỗi lần skhai thác bạn khởi động lại chu kỳ:

sed -e :t -e '$!N;/\n[[:lower:]]/s/\n/ /;tt' -e 'P;D' infile

1
Tôi nghĩ rằng tôi thấy những gì đang diễn ra ở đây, nhưng một câu trả lời mở rộng sẽ giúp những người trong chúng ta không sử dụng vòng lặp sed và không gian mô hình rất thường xuyên.
Joe

@Joe - Ý bạn là gì khi "không thường xuyên sử dụng không gian mẫu" ? Đó là nơi gần như tất cả các hoạt động diễn ra - không gian lưu trữ là "không gian lưu trữ" - bạn không thể làm gì với dữ liệu trong khi đó. Dù sao, tôi đã giải thích chi tiết về cách thức một N;P;Dchu kỳ hoạt động ở đây vì vậy tôi sẽ không đi qua nó một lần nữa. Sự khác biệt ở đây là test - để kiểm tra xem có thứ gì được thay thế hay không - nếu thử nghiệm thành công thì chúng tôi sẽ phân nhánh lên đầu tập lệnh, nếu không, điều đó có nghĩa là không có gì được thay thế và P;Dđược thực thi. Hãy cho tôi biết nếu nó vẫn chưa rõ ràng.
don_crissti

3

Sử dụng sedfmt:

$ sed -e '1n; s/^[[:upper:]]/\n&/' input.txt | fmt
This is one sentence that is broken.

However this is a good one.

And this one is somehow, broken into many.

Tập lệnh sed chèn một dòng mới trước mỗi dòng bắt đầu bằng chữ in hoa (ngoại trừ dòng đầu tiên đầu tiên). sedĐầu ra của sau đó được dẫn vào fmtđể định dạng lại các đoạn kết quả.

Hoặc sử dụng parnếu bạn đã cài đặt nó. Đó là một đoạn trích khác, nhưng có nhiều khả năng hơn fmt, với nhiều tính năng và tùy chọn hơn.

Lưu ý rằng sẽ có một dòng trống giữa mỗi đoạn. Các đoạn nên được tách biệt với nhau bằng ít nhất một dòng trống. Không có các dòng trống, toàn bộ mẫu đầu vào của bạn được định dạng lại thành một đoạn nhiều câu, ví dụ:

$ fmt input.txt
This is one sentence that is broken.  However this is a good one.
And this one is somehow, broken into many.

Nếu bạn cần xóa các dòng trống sau khi định dạng lại, hãy chuyển nó qua sedmột lần nữa - nhưng điều này sẽ xóa TẤT CẢ các dòng trống, bao gồm bất kỳ dòng nào có thể có trong đầu vào ban đầu. ví dụ

$ sed -e '1n; s/^[[:upper:]]/\n&/' input.txt | fmt | sed -e '/^$/d'
This is one sentence that is broken.
However this is a good one.
And this one is somehow, broken into many.

3

Một cách khác bạn có thể làm điều này là:

perl -lpe '$\ = /\.$/ ? $/ : $"' data

trong đó: $\=> ORS, $/=> IRS= \n, $"=space

perl -pe '$_ .= <>, eof or redo if s/[^.]\K\n/ /' data

sed -e '
   :a
      /\.$/!N
      s/\n/ /
   ta
' data

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.