Yalnızca yeni satırları değiştirmek için daha iyi bir yol olmalı mı?


27

Cümle başına bir satır yazma alışkanlığım var çünkü genellikle LaTex'e bir şeyler derlerim ya da satır sonlarının yok sayılacağı başka bir formatta yazıyorum. Yeni bir paragrafın başlangıcını belirtmek için boş bir satır kullanıyorum.

Şimdi, bu tarzda yazılmış ve sadece düz metin olarak göndermek istediğim bir dosyam var. Tüm tek satır izlerini kaldırmak istiyorum ancak çift satır izlerini bozulmadan bırakın. Yaptığım şey bu:

sed 's/$^/NEWLINE/' file.txt | awk '{printf "%s ",$0}' | sed 's/NEWLINE/\n\n/g' > linebreakfile.txt

Bu, boş satırları dosyada görünmediğinden emin olduğum bir metinle değiştirir: NEWLINEve sonra tüm satır sonlarından awk ile kurtulur (bazı web sitelerinde bu numarayı buldum) ve sonra NEWLINEgerekli iki satır aralığı ile s'leri değiştirir. .

Bu oldukça basit bir şey yapmak için uzun soluklu bir yol gibi görünüyor. Daha basit bir yolu var mı? Ayrıca, birden fazla boşluğu (bazen nedense sürünen) tek boşluklarla değiştirmenin bir yolu olsaydı, bu da iyi olurdu.

Ben emacs kullanıyorum, bu yüzden bazı emac'lere özgü bir numara varsa, iyi bir saf veya saf awk versiyonu görmeyi tercih ederim.


İlk sed komutta ^ $ dedin, $ ^ değil.
kullanıcı bilinmeyen

@ kullanıcı evet, ben yaptım.
Seamus,

Daha kolay bir yolu tüm satır sonlarını kaldırmak için: tr -d "\n".
jfg956

Yanıtlar:


18

Bu gibi awk kullanabilirsiniz:

$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } ' test

Veya sonunda ekstra bir yeni hatta ihtiyacınız varsa:

$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } END { print ""; } ' test

Veya paragrafları yeni bir satırla ayırmak istiyorsanız:

$ awk ' /^$/ { print "\n"; } /./ { printf("%s ", $0); } END { print ""; } ' test

Bu awk komutları, kalıplarla korunan eylemleri kullanır:

/regex/

veya

END

Aşağıdaki işlem yalnızca desen geçerli çizgiyle eşleşirse gerçekleştirilir.

Ve ^$.karakterlerin, normal ifadelerde, ^satırın başlangıcı $, bitişi ve .keyfi bir karakterle eşleştiği özel bir anlamı vardır .


Bu iyidir, ancak paragraflar arasındaki boş çizgiyi tutmayı tercih ederim . İlk baskı komutunda bir yere fazladan yeni bir satır ekleyerek böyle bir şey yapabileceğinizi varsayıyorum. Ayrıca, ne olduğunu /./yapıyor: bunu gibi ve hareket gibi görünüyor elseiçin /^$/dize maç, doğru mu?
Seamus,

1
@Seamus, elbette - yalnızca ilk baskının yerini al (yanıtı güncelle) - /./, en az bir karakter uzunluğundaki tüm satırlarla eşleşir, yani yalnızca boş satırlarla eşleşen / ^ $ / deseninin tamamlayıcısıdır.
maxschlepzig

9

Paragrafların boş satırlarla ayrıldığı paragrafa göre dosya paragrafını işlemek için Awk veya Perl'in paragraf modunu kullanın.

awk -vRS= '
  NR!=1 {print ""}      # print blank line before every record but the first
  {                     # do this for every record (i.e. paragraph):
    gsub(" *\n *"," "); # replace newlines by spaces, compressing spaces
    sub(" *$","");      # remove spaces at the end of the paragraph
    print
  }
'
perl -000 -pe '             # for every paragraph:
  print "\n" unless $.==1;  # print a blank line, except before the first paragraph
  s/ *\n *(?!$)/ /g;        # replace newlines by spaces, compressing spaces, but not at the end of the paragraph
  s/ *\n+\z/\n/             # normalize the last line end of the paragraph
'

Tabii ki, bu (La) TeX’i ayrıştırmadığından, yorumları, sözlü ortamları ve diğer özel sözdizimlerini korkunç derecede kısaltacaktır. DeTeX veya diğer (La) TeX-to-text dönüştürücülere bakmak isteyebilirsiniz .


8

Sed Çözüm

$ sed -e ':a;N;$!ba;s/\(.\)\n/\1 /g' -e 's/\n/\n\n/' test.text

Bu çözümde :abir etiket yarattığınızı ve akomutu kullanmayacağınızı unutmayın .

Birden Çok Boşluğu Değiştirme

Kullanım tr:$ tr -s ' ' <test.text


8

Doğru anladıysam, boş bir satır iki ardışık yeni satırı belirtir \n\n.

Öyleyse, olası bir çözüm, yeni satırların tüm tekil oluşumlarını ortadan kaldırmak olacaktır.

Perl'de, bir bakış açısı iddiası bunu başarmanın bir yoludur:

$ perl -0777 -i -pe 's/\n(?=[^\n])//g' test
  • -0777Bayrak etkin şekilde tek bir dize halinde tüm dosyayı slurps
  • -p perl'e çalışmakta olduğu dizeyi varsayılan olarak yazdırmasını söyler
  • -i yerinde düzenlemeyi belirtir
  • Global eşleştirme, tüm yeni newline oluşumlarının ele alınmasını sağlar

Bunun bir sorunu, cümleler arasında boşluk olmamasıdır.
Steven D,

6

(eski bir soruyu canlandırmak)

Bu tam olarak ne fmtve parparagraf reformatting için olduğu gibi görünüyor . Sizin gibi (ve birçok program gibi) paragraf sınırlarını bir (veya daha fazla) boş satır olarak tanımlarlar. Metninizi bunlardan birinin içinden geçirmeyi deneyin.

fmt standart bir unix yardımcı programıdır ve GNU Coreutils'te bulunabilir.

parhttp://www.nicemice.net/par/ adresindefmt bulunabilen Adam M. Costello tarafından yazılmış , çok büyük ölçüde geliştirilmiş bir kitaptır. Şimdi pkg için yeni bir bakıcı olmasına rağmen.).


6
sed -e'/./{H;$!d;}' -e'x;s/\n//g'

sedHerhangi bir satırı Hen az bir karakter içeren eski alana ekleyecektir . Hemen dburada, belki de sonuncusu hariç bütün bunları seçer. Kalan tek satırlar boşluktur ve sede xtutma ve desen alanlarını değiştirdiğinde ve biriken tüm \newline karakterlerini silerken bu satırlardadır .

Yalnızca <tabs> veya <boşluklar> içeren satırların boş sayılmasını istiyorsanız , /./yukarıdaki adresi ile değiştirin /[^[:blank:]]/. Ayrıca boşlukları sıkmak için şunu yapın:

 sed -e'/./{H;$!d;}'    \
     -e'x;s/\n//g'      \
     -e's/\([[:blank:]]\)*/\1/g'

5

Gilles 'un perl ve awk kompakt örneklerini gördükten sonra, bunu göndermekte isteksizdim, ama zaten alıştırmadan geçtim ve makul bir şekilde belgelenen, işlevsel bir senaryo; bu nokta tek başına bazılarının ilgisini çekebilir .. (yorumlarla sed! :)

Bu komut dosyası, boşluklar olsa bile boş satırları boş olarak değerlendirir.
Metindeki birden çok boşluk, tek bir alana yoğunlaştırılır.
İzleyen boşluk, metin satırlarından kaldırıldı. Ardışık boş satırlar tek bir satıra daraltılır. Komut üst ve alt boş satırları bozulmadan bırakır.

En önemsiz komut dosyalarından daha fazlası için sed, yapılandırılmış bir biçimde, ayrı bir komut dosyası olarak çok daha kolay yazılabilir. İşte böyle bir örnek.

genişletilmiş regex sözdizimi
çağrısı kullanarak : $ sed -rf komut dosyası metin dosyası

  :first-empty-line
  #================
  /^[[:space:]]*$/ { # if pattern-space is empty...
      $q  # last line # flush-quit 
      n   # pattern-flush=nextline-continue

      :subsequent-empty-line
      #=====================
      /^[[:space:]]*$/ { # if pattern-space is empty...
          $d        # last line # pattern-delete-cycle
          N         # pattern+=nl+nextline
          s/.*\n//  # scrap the leading 'blank' line
          t subsequent-empty-line # branch-on-substitute
      }
  }

  :text-line
  #=========
  $q                       # last line # flush-quit 
  s/^(.*)[[:space:]]*/\1/  # trim trailing whitespace
  s/ +/ /g                 # condense mulltiple spaces
  N                        # pattern+=nl+nextline
  /^.*\n[[:space:]]*$/ { # if newly-read line is blank 
      P          # pattern-first-line-print
      s/^.*\n//  # remove the leading 'text' line
      t first-empty-line   # branch-on-substitute
  }
  # read line is text
  s/\n/ /      # replace \n with a space
  t text-line  # branch-on-substitute

Not: flushyorumlarda şu anlama gelir: desen alanını sed'in iç stdout işlemine gönderin. Stdout'a kesin bir baskı anlamına gelmez. Çıktı sed'in -nseçeneğine bağlıdır . Örneğin. qKomut aracı floş çıkın ve bu iki parçacıkları karşılaştırın ...: echo x |sed -e qbaskılar x, echo x |sed -ne qbaskılar hiçbir şey kullanarak oysa pbağlı iki veya bir defa 'x' yazdıracak komutu -nseçeneği.


İyi yorumlarınız için +1. Hiç yorum yapmayan çok fazla program gördüm.
David Cary

4

İşte sedtüm satırları sed"tutma alanı" ile birleştiren başka bir çözüm. Böylece, desen eşleştirme için nihayet "kalıp alanı" na kopyalanan uzun bir dize elde edeceğiz.

Newlines son uzun dizgide sed'' desen alanı '' içinde korunacağından , çift çizgiler şeklinde boş satırlar [^\n]\n\n[^\n]eşleştirilebilir ve değiştirilebilir [^\n]\n[^\n].

Daha fazla bilgi için bkz. Sed ve Çok Hatlı Arama ve Değiştirme .

text='
line 1

line 2
line 3





line 4


line     5



line 6
line 7

line 8
'

# FreeBSD sed
# first sed deletes first / last line if empty and squeezes multiple spaces
printf '%s' "$text" |
sed -e '1{/^$/d;}' -e '${/^$/d;}' -e '/[[:space:]]\{2,\}/s// /g' | 
sed -n -e '1h;1!H;${;g;/\([^[:cntrl:]]\)\n\n\([^[:cntrl:]]\)/s//\1\
\2/g;p;}' |
nl -b a


# GNU sed
# alternative using ...;x;... instead of ...;g;...
# cf. man sed | less -p '\]x'
printf '%s' "$text" |
gsed -e '1{/^$/d;}' -e '${/^$/d;}' -e '/[[:space:]]\{2,\}/s// /g' | 
gsed -E -n '1h;1!H;${;x;/([^\n])\n\n([^\n])/s//\1\
\2/g;p;}' | 
nl -b a


# remove all the single linebreaks but leave the double linebreaks intact
printf '%s' "$text" | 
   sed -n -e '1h;1!H;${;g;/\([^[:cntrl:]]\)\n\([^[:cntrl:]]\)/s//\1 \2/g;p;}' | 
   nl -b a

3

Bu eski okul olabilir:

(echo ".pl 1" ; echo ".ll 80" ; echo ".ad l" ; cat your_file) | nroff

Bu, metninizi sola ( .ad l), 80 ( .ll 80) uzunluğunda bir çizgi olacak şekilde çıkartacaktır . Sayfa uzunluğu seçeneği ( .pl), metin işlemcisine 1 sayfa uzunluğu için sayfa dolgusu yapmalarını söyler; bu nedenle sayfa dolgusu olmaz.

Tüm paragraflarınızı tek bir satırda görmek istiyorsanız, aşağıdakiler için çok sayıda kullanabilirsiniz .ll:

(echo ".pl 1" ; echo ".ll 1000000" ; echo ".ad l" ; cat your_file) | nroff

daha fazla biçimlendirme seçeneği için man 7 groff .


1

Emacs'ta bazen bunu kullanıyorum regex:

^J\([^^J]\) -> \1

Anlamına geliyor:

her yeni satırın yerini yeni satır olan DEĞİL, yalnızca yeni satır olan, yeni satırın ardından gelen paragraftaki tüm yeni satırlardan kurtulurum ama paragrafları tutarım (iki satır yeni satır)


0

auto-fill-modeAnlaşılıyor ki , emacs basit kullanım durumlarım için oldukça iyi bir iş çıkarmış M-q...


Neyin ayrıntısı ne auto-fill-modekadar aktif olduğunuza bağlıdır.
dmckee
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.