Il doit y avoir un meilleur moyen de replace les nouvelles lignes seulement?

J'ai l'habitude d'écrire une ligne par phrase parce que je comstack généralement des choses à LaTex, ou j'écris dans un autre format où les sauts de ligne sont ignorés. J'utilise une ligne vide pour indiquer le début d'un nouveau paragraphe.

Maintenant, j'ai un file écrit dans ce style que je voudrais simplement envoyer en text clair. Je veux supprimer tous les sauts de ligne, mais laisser les sauts de ligne doubles intacts. C'est ce que j'ai fait:

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

Cela remplace les lignes vides par un text qui, je l'espère, n'apparaît pas dans le file: NEWLINE et puis il se débarrasse de tous les sauts de ligne avec awk (j'ai trouvé ce truc sur un site web) puis remplace le NEWLINE par le requirejs deux sauts de ligne.

Cela semble être une façon longue et sinueuse de faire une chose assez simple. Y a-t-il un moyen plus simple? En outre, s'il y avait un moyen de replace plusieurs espaces (qui se glissent parfois pour une raison quelconque) avec des espaces uniques, ce serait bien aussi.

J'utilise emacs, donc s'il y a un truc spécifique emacs c'est bien, mais je préfère voir une version pure sed ou pure awk.

Vous pouvez utiliser awk comme ceci:

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

Ou si vous avez besoin d'une nouvelle ligne supplémentaire à la fin:

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

Ou si vous voulez séparer les paragraphes par une nouvelle ligne:

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

Ces commands awk utilisent des actions qui sont gardées par des patterns:

 /regex/ 

ou

 END 

Une action suivante n'est exécutée que si le motif correspond à la ligne en cours.

Et le ^$. les caractères ont une signification particulière dans les expressions régulières, où ^ correspond au début de la ligne, $ la fin et . un caractère arbitraire.

Solution Sed

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

Notez que dans cette solution :a crée une label et n'utilise pas la command a.

Remplacer plusieurs espaces

Utilisez tr : $ tr -s ' ' <test.text

Si j'ai bien compris, une ligne vide implique deux returns consécutifs, \n\n .

Si c'est le cas, une solution possible serait d'éliminer toutes les occurrences singulières de nouvelles lignes.

En Perl, une assertion de lookahead est une façon d'y parvenir:

 $ perl -0777 -i -pe 's/\n(?=[^\n])//g' test 
  • Le drapeau -0777 efficacement le file entier en une seule string
  • -p indique à perl d'imprimer la string sur laquelle il travaille par défaut
  • -i spécifie l'édition sur place
  • La correspondance globale garantit que toutes les occurrences de nouvelle ligne sont traitées

Utilisez le mode paragraphe Awk ou Perl pour traiter un file paragraphe par paragraphe, où les paragraphes sont séparés par des lignes vides.

 awk -vRS= ' NR!=1 {print ""} # print blank line before every record but the first { # do this for every record (ie 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 ' 

Bien sûr, puisque cela n'parsing pas le (La) TeX, il va horriblement mutiler les commentaires, les environnements verbatim et d'autres syntaxes spéciales. Vous pouvez regarder dans DeTeX ou d'autres convertisseurs (La) TeX-to-text.

(relancer une question ancienne)

Cela semble être exactement ce que fmt et par sont pour – reformatting de paragraphe. Comme vous (et aussi comme beaucoup de programmes), ils définissent des limites de paragraphe comme une (ou plusieurs) lignes vides. Essayez de passer votre text à travers l'un d'eux.

fmt est un utilitaire unix standard et peut être trouvé dans GNU Coreutils.

par est un fmt grandement amélioré écrit par Adam M. Costello qui peut être trouvé à http://www.nicemice.net/par/ (il a également été emballé pour plusieurs dissortingbutions, y compris debian – je l'ai emballé pour debian en janvier 1996, bien qu'il y ait un nouveau mainteneur pour le package maintenant.).

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

sed appenda n'importe quelle ligne à H old space qui contient au less un seul caractère. Tout de suite, il élimine tous ces éléments sauf peut-être le dernier. Les seules lignes qui peuvent restr sont des blancs, et c'est sur ces lignes que sed e x change les espaces hold et pattern et supprime tous les \n ewlines accumulés.

Si vous voulez que les lignes qui ne contiennent que <tabs> ou <spaces> soient vierges, remplacez l'adresse /./ ci-dessus par /[^[:blank:]]/ . Pour également presser les espaces, procédez comme suit:

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

Après avoir vu les exemples compacts de perl et awk de Gilles, j'étais réticent à postr ceci, mais j'avais déjà fait l'exercice, et c'est un script fonctionnel, qui est documenté de manière raisonnable; ce point seul peut être intéressant pour certains .. (sed avec des commentaires 🙂

Ce script considère les lignes vides comme étant blanches même si elles contiennent des espaces.
Les espaces multiples dans le text sont condensés en un seul espace.
Les espaces de traînage sont supprimés des lignes de text. Les lignes vides consécutives sont réduites à une seule ligne. Le script laisse les lignes vides du haut et du bas intactes.

Pour tout autre chose que les scripts les plus simples, sed peut être écrit beaucoup plus facilement sous forme structurée, en tant que file de script séparé. Voici un tel exemple.

en utilisant la syntaxe regex étendue
appelez: $ sed -rf script text-file

  :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/ # sortingm 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 

Note: flush , dans les commentaires, signifie: envoyer l'espace de patron à la gestion stdout interne de sed. Cela ne signifie pas une printing définitive à stdout. La sortie dépend de l'option -n de sed. par exemple. la command q signifie vider et quitter … Comparer ces deux extraits: echo x |sed -eq imprime x, echo x |sed -ne q n'imprime rien, alors echo x |sed -ne q utilisant la command p imprimerait 'x' deux ou echo x |sed -ne q fois, selon l'option -n .

Voici encore une autre solution sed qui concatène toutes les lignes dans sed "hold space" afin que nous obtenions une longue string qui est finalement copiée dans le "pattern space" pour la correspondance de motifs.

Comme les lignes de return seront conservées dans la string longue finale dans sed "espace de motif", les lignes vides en termes de saut de ligne doubles [^\n]\n\n[^\n] peuvent être appariées et modifiées en [^\n]\n[^\n] .

Pour plus d'informations, voir, par exemple, sed et Multi-Line Search and Replace .

 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 -ba # 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 -ba # 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 -ba 

Cela pourrait être vieille école:

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

Cela affichera votre text aligné à gauche ( .ad l ), avec une longueur de ligne de 80 ( .ll 80 ). L'option de longueur de page ( .pl ) indique au processeur de text d'effectuer un remplissage de page pour une longueur de page de 1, donc pas de remplissage de page.

Si vous voulez tous vos paragraphes sur une seule ligne, vous pouvez utiliser un grand nombre pour .ll :

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

man 7 groff pour plus d'options de formatting.

Dans Emacs, j'utilise parfois cette regex :

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

Veux dire:

replace chaque nouvelle ligne qui est suivie par quelque chose qui n'est PAS une nouvelle ligne avec seulement la chose, qui a suivi la nouvelle ligne De cette façon, je me débarrasse de toutes les lignes dans un paragraphe, mais garder les paragraphes (double-newlines)

Il s'avère qu'en mode auto-fill-mode on, emacs fait un très bon travail pour mes cas d'utilisation simples avec juste Mq