web-dev-qa-db-ja.com

単一の改行のみを置き換えるより良い方法があるはずですか?

私は通常LaTexにコンパイルするため、または改行が無視される他の形式で書くため、1文につき1行を書く習慣があります。空白行を使用して、新しい段落の開始を示しています。

これで、このスタイルで記述されたファイルがあり、プレーンテキストとして送信したいだけです。すべての単一の改行を削除したいが、二重の改行はそのままにしたい。これは私がやったことです:

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

これは、空の行をファイルに表示されないと確信しているテキストに置き換えます:NEWLINEそして、すべての改行をawkで削除し(一部のWebサイトでそのトリックを見つけました)、次にNEWLINEsを必須の2つに置き換えます改行。

これは、かなり単純なことをするための長い道のりのようです。より簡単な方法はありますか?また、複数のスペース(何らかの理由で侵入する場合がある)を単一のスペースに置き換える方法があった場合も、それで十分です。

私はemacsを使用しているので、emacs固有のトリックが良い場合は、純粋なsedまたは純粋なawkバージョンが見たいと思います。

28
Seamus

次のようにawkを使用できます。

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

または、最後に追加の改行が必要な場合:

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

または、段落を改行で区切りたい場合:

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

これらのawkコマンドは、パターンによって保護されているアクションを利用します。

/regex/

または

END

次のアクションは、パターンが現在の行と一致する場合にのみ実行されます。

また、^$.文字は正規表現で特別な意味を持ちます。ここで、^は行の先頭に一致し、$は末尾に一致し、.は任意の文字に一致します。

19
maxschlepzig

AwkまたはPerlの 段落モード を使用して、ファイルを段落ごとに処理します。段落は空白行で区切られます。

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
'

もちろん、これは(La)TeXを解析しないため、コメント、逐語的環境、その他の特別な構文をひどく傷つけてしまいます。 DeTeX または他の(La)TeX-to-textコンバーターを調べてみてください。

Sedソリューション

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

このソリューションでは、:aはラベルを作成しており、aコマンドを使用していません。

複数のスペースを置き換える

trを使用:$ tr -s ' ' <test.text

8
Steven D

私が正しく理解していれば、空の行は2つの連続した改行\n\nを意味します。

もしそうなら、1つの可能な解決策は、改行のすべての特異な発生を排除することです。

Perlでは、先読みアサーションはこれを実現する1つの方法です。

$ Perl -0777 -i -pe 's/\n(?=[^\n])//g' test
  • -0777フラグは、ファイル全体を1つの文字列に効果的に丸呑みします
  • -pは、Perlにデフォルトで処理中の文字列を出力するように指示します
  • -iは、インプレース編集を指定します
  • グローバルマッチングにより、すべての単一改行の発生が確実に処理されます。
8
Zaid

(古代の質問を復活させる)

これは、fmtparがまさに目的であるようです-段落の再フォーマット。あなた(そして多くのプログラム)のように、段落の境界を1つ(または複数)の空白行として定義します。これらのいずれかにテキストをパイプしてみてください。

fmtは標準のUNIXユーティリティであり、GNU Coreutilsにあります。

parはAdam M. Costelloによって大幅に強化されたfmtであり、 http://www.nicemice.net/par/ にあります(これはまた、debianを含むいくつかのディストリビューション用にパッケージ化されました-私は1996年1月にdebian用にパッケージ化しましたが、現在pkgの新しいメンテナがいます。

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

sedは、少なくとも1文字を含むHoldスペースに任意の行を追加します。それはすぐにdeleterを即座に削除し、おそらく最後のものを除きます。残ることができる唯一の行は空白であり、sed e xが保留スペースとパターンスペースを変更し、蓄積されたすべての\newline文字を削除するときに、これらの行にあります。

<tabs>または<spaces>のみを含む行を空白と見なしたい場合は、上記の/./アドレスを/[^[:blank:]]/に置き換えます。スペースを絞るには、次のようにします。

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

次に、すべての行をsedの「ホールドスペース」に連結して、最後にパターンマッチングのために「パターンスペース」にコピーされる1つの長い文字列を取得する別のsedソリューションを示します。

改行はsedの「パターンスペース」の最後の長い文字列に保持されるので、二重改行[^\n]\n\n[^\n]に関する空の行を照合して[^\n]\n[^\n]に変更できます。

詳細については、たとえば sedおよび複数行の検索と置換 を参照してください。

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
4
deso

これは古い学校かもしれません:

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

これにより、テキストが左揃え(.ad l)で、行の長さが80(.ll 80)で出力されます。ページ長オプション(.pl)は、テキストプロセッサにページ長1のページパディングを行うように指示するため、ページパディングはありません。

すべての段落を1行にしたい場合は、.llに大きな数を使用できます。

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

man 7 groff より多くのフォーマットオプション。

3
jfg956

Emacsでは、これを時々使用しますregex

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

手段:

改行ではないものに続くすべての改行を、改行に続くもので置き換えるこうすることで、段落内のすべての改行を削除しますが、段落は保持します(二重改行)

1
emacs-user

auto-fill-modeオン、emacsはM-q...

0
Seamus