web-dev-qa-db-fra.com

Il doit y avoir un meilleur moyen de remplacer uniquement des nouvelles lignes célibataires?

J'ai l'habitude d'écrire une ligne par phrase parce que je compile généralement des choses à la latex, ou je vous écris dans un autre format où les pauses de la ligne sont ignorées. J'utilise une ligne vide pour indiquer le début d'un nouveau paragraphe.

Maintenant, j'ai un fichier écrit dans ce style que je voudrais juste envoyer en tant que texte brut. Je veux éliminer tous les gilles simples, mais laisser les doubles gelles 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

Ceci remplace les lignes vides avec un texte que je suis confiant n'apparaît pas dans le fichier: NEWLINE _ Et puis il se débarrasse de toutes les pauses de ligne avec AWK (j'ai trouvé cette astuce sur un site Web), puis il remplace la NEWLINEs avec les deux chevichets requis.

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

J'utilise Emacs, donc s'il y a des trucs spécifiques d'Emacs, c'est bien, mais je préfère voir une version pure SED ou Pure Awk.

28
Seamus

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 souhaitez séparer les paragraphes par une nouvelle ligne:

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

Ces commandes AWK utilisent des actions qui sont gardées par des modèles:

/regex/

ou

END

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

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

19
maxschlepzig

Utilisez AWK ou PERL mode de paragraphe pour traiter un paragraphe de fichier par paragraphe, où les paragraphes sont séparés par des lignes vierges.

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
'

Bien sûr, étant donné que cela n'analyse pas le (LA) Tex, il sera horriblement mutilé des commentaires, des environnements verbatim et une autre syntaxe spéciale. Vous voudrez peut-être examiner Detex ou d'autres convertisseurs Tex-to-Text.

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éation d'une étiquette et n'utilise pas la commande a.

Remplacer plusieurs espaces

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

8
Steven D

Si j'ai bien compris, une ligne vide implique deux nouvelles lignes consécutives, \n\n.

Si tel est le cas, une solution possible consisterait à éliminer toutes les occurrences singulières des nouvelles lignes.

À Perl, une affirmation de lunette est une solution pour y parvenir:

$ Perl -0777 -i -pe 's/\n(?=[^\n])//g' test
  • Le -0777 le drapeau est effectivement slurps le fichier entier dans une seule chaîne
  • -p indique à Perl d'imprimer la chaîne qu'il fonctionne par défaut
  • -i Spécifie l'édition de lieu
  • La correspondance globale garantit que toutes les occurrences simples simples sont traitées
8
Zaid

(faire revivre une question antique)

Cela semble être exactement ce que fmt et par sont à reformatage de paragraphes. Comme vous (et aussi comme de nombreux programmes), ils définissent les limites de paragraphe comme une (ou plusieurs) lignes vides. Essayez de tuyer votre texte à travers l'un d'entre eux.

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

par est une très améliorée fmt écrite par Adam M. Costello, qui peut être trouvée à http://www.nicemice.net/par/ (il a Aussi été emballé pour plusieurs distributions, y compris Debian, je l'ai emballé pour Debian en janvier 1996, bien qu'il y ait un nouveau responsable de la PKG maintenant.).

8
cas

Après avoir vu des exemples de Perl et Awk Compact, j'étais réticent à poster cela, mais j'avais déjà passé l'exercice, et c'est un script fonctionnel, raisonnablement documenté; Ce seul point peut-il intéresser certains .. (sed avec des commentaires! :)

Ce script considère que les lignes vides soient vides, même si elles contiennent des espaces.
Plusieurs espaces dans le texte sont condensés à un seul espace.
Espace de fuite est supprimé des lignes de texte. Les lignes vides consécutives sont effondrées à une seule ligne. Le script laisse des lignes vierges supérieures et inférieures intactes.

Pour quelque chose de plus que les scripts les plus triviaux, SED peut être écrit beaucoup plus facilement sur une forme structurée, en tant que fichier de script distinct. Voici un exemple exemple.

en utilisant la syntaxe de regex étendue
[.____] appeler: $ sed -rf script texte-fichier

  :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

Remarque: flush, dans les commentaires, moyens: Envoyez l'espace de motif à la gestion interne de STDOUT interne de SED. Cela ne signifie pas une impression définitive à stdout. La sortie dépend de l'-n option. par exemple. Les moyens de commande qrincer et quitter ... Comparez ces deux extraits: echo x |sed -e q imprime x, echo x |sed -ne q Imprime rien, alors que l'utilisation de la commande p imprimerait deux fois ou une fois, en fonction de la -n option.

5
Peter.O

Dans Emacs, j'utilise parfois ce regex:

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

Veux dire:

remplacez chaque nouvelle ligne qui est suivie de quelque chose qui n'est pas une nouvelle ligne avec seulement la chose, qui a suivi la nouvelle ligne de cette façon de vous débarrasser de toutes les nouvelles lignes dans un paragraphe, mais gardez les paragraphes (double-litline)

1
emacs-user

Il s'avère que avec auto-fill-mode ON, EMACS fait un très bon travail pour mes cas d'utilisation simples avec juste M-q...

0
Seamus