Bagaimana cara memperbaiki garis yang rusak di tempat yang salah?

11

File teks saya terlihat seperti ini:

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

Saya ingin menghapus karakter baris baru untuk setiap baris yang diikuti oleh baris yang dimulai dengan huruf kecil.

Jadi ini seharusnya:

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

Bagaimana saya bisa melakukan ini?

Sunting: Ada beberapa jawaban yang sangat bagus di sini, tetapi saya memilih untuk menerima yang pertama yang berhasil dan paling awal. Terima kasih banyak semuanya!


sumber
1
Getah? Masalahnya adalah bahwa Anda tidak benar-benar menyatakan aturan untuk melanggar kalimat yang tepat. Apakah Anda ingin meletakkan semuanya hingga dan termasuk tanda baca akhir kalimat pada satu baris? Tetapi bagaimana jika Anda memiliki kalimat yang panjang dan itu berjalan di tepi jendela tampilan Anda?
jamesqf
1
Saya ingin tahu apa yang sebenarnya Anda coba selesaikan? Mungkin Anda harus menggunakan format markdown?
Wildcard
@JeffSchaller Terima kasih atas pengingatnya! Entah bagaimana saya telah melewatkannya. :)

Jawaban:

7

mencoba

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

dimana

  • $NF !~ /\.$/ garis kecocokan di mana elemen terakhir tidak berakhir dengan titik,
  • { printf "%s ",$0 cetak baris ini dengan spasi tambahan, dan tanpa umpan baris,
  • next ; } ambil baris berikutnya,
  • {print;} dan cetak.

Saya yakin akan ada sedopsi.

Catatan: ini akan bekerja dengan baris yang diakhiri dengan titik, namun kondisi dalam kalimat yang dimulai dengan huruf besar tidak akan digabungkan. Lihat jawaban Stéphane Chazelas.

Archemar
sumber
Jika Anda suka pintar (banyak yang tidak)awk 'ORS=$NF~/\.$/?"\n":" "'
dave_thompson_085
10

Dengan awk:

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

Artinya, jangan tambahkan pemisah rekaman untuk setiap baris (ORS kosong). Tapi tambahkan pemisah rekaman sebelum baris saat ini jika tidak pada baris pertama dan baris saat ini tidak dimulai dengan huruf kecil. Sebaliknya, ganti karakter spasi sebagai gantinya, kecuali pada baris pertama.

Stéphane Chazelas
sumber
Ketika saya menjalankan ini beberapa pasang kata digabungkan. Misalnya And thisone issomehow, broken intomany.saya tidak tahu awktetapi haruskah garis digabungkan dengan <space>tambahan RS? Atau apakah ini kesalahan pengguna?
B Layer
@BLayer, terlihat dengan baik, terima kasih. Harus diperbaiki sekarang.
Stéphane Chazelas
Tidak masalah. Meskipun orang bertanya-tanya dari mana ke-11 suara positif itu berasal. Pasti menyenangkan memiliki orang, anggap saja kau selalu benar. ;)
B Layer
4

Dalam perl:

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

Secara teknis Anda ingin mengganti "baris baru diikuti dengan huruf kecil" dengan "spasi dan huruf kecil", yang merupakan inti dari skrip perl di atas:

  1. Baca di input ke string input.
  2. Perbarui inputvariabel untuk menjadi hasil pencarian & ganti operasi.
  3. Cetak nilai baru.
Jeff Schaller
sumber
1
bagus !! diterjemahkan menjadi one-liner, perl -0777 -pe 's/\n([a-z])/ $1/g'dan dapat juga dilakukan dengan GNU sed as sed -zE 's/\n([a-z])/ \1/g'(dengan asumsi input tidak memiliki karakter nol)
Sundeep
3
@ Simpan, atau perl -Mopen=locale -0777 -pe 's/\n(?=[[:lower:]])/ /g'agar tidak terbatas pada surat ASCII.
Stéphane Chazelas
4

Dengan sedAnda dapat menggunakan N;P;Dsiklus (sehingga selalu memiliki dua baris dalam ruang pola dan jika karakter pertama setelah baris baru adalah huruf kecil kemudian ganti baris baru dengan spasi) dan test - cara itu setelah setiap substitusi Anda memulai kembali siklus:

sed -e :t -e '$!N;/\n[[:lower:]]/s/\n/ /;tt' -e 'P;D' infile
don_crissti
sumber
1
Saya pikir saya melihat apa yang terjadi di sini, tetapi jawaban yang diperluas akan membantu kita yang tidak sering menggunakan loop dan ruang pola.
Joe
@ Jo - apa maksudmu dengan "tidak terlalu sering menggunakan pola ruang" ? Di situlah hampir semua operasi berlangsung - ruang penahanan adalah "ruang penyimpanan" - Anda tidak dapat melakukan apa pun dengan data saat itu ada. Bagaimanapun, saya telah menjelaskan secara rinci bagaimana sebuah N;P;Dsiklus bekerja di sini sehingga saya tidak akan membahasnya lagi. Perbedaannya di sini adalah test - untuk memeriksa apakah sesuatu telah diganti atau tidak - jika tes berhasil maka kita bercabang ke bagian atas skrip, jika tidak berarti tidak ada yang diganti dan P;Ddieksekusi. Beri tahu saya jika masih belum jelas.
don_crissti
3

Menggunakan seddan fmt:

$ 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.

Skrip sed menyisipkan baris baru sebelum setiap baris yang dimulai dengan huruf kapital (kecuali untuk baris input pertama). sedKeluaran kemudian disalurkan ke fmtuntuk memformat ulang paragraf yang dihasilkan.

Atau gunakan parjika Anda sudah menginstalnya. Ini adalah pembaru paragraf lain, tetapi jauh lebih mampu daripada fmt, dengan lebih banyak fitur dan opsi.

Perhatikan bahwa akan ada garis kosong antara setiap paragraf. Paragraf harus dipisahkan satu sama lain dengan setidaknya satu baris kosong. Tanpa baris kosong, seluruh sampel input Anda diformat ulang sebagai paragraf multi-kalimat tunggal, misalnya:

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

Jika Anda perlu menghapus garis-garis kosong setelah memformat ulang hanya pipa melalui sedlagi - tetapi ini akan menghapus SEMUA garis-garis kosong, termasuk yang mungkin ada di input asli. misalnya

$ 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.
cas
sumber
3

Cara lain yang dapat Anda lakukan adalah:

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

dimana: $\=> ORS, $/=> IRS= \n, $"=space

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

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

sumber
2

Python 3

import re
print(re.sub(r'\n([a-z])', r' \1', open('file.txt').read(), flags=re.MULTILINE))

Ini adalah regex / substitusi yang sama dengan jawaban Jeff

wjandrea
sumber