Comment réparer les lignes interrompues aux mauvais endroits?

11

Mon fichier texte ressemble à ceci:

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

Je veux supprimer le caractère de fin de ligne pour toute ligne qui est suivie d'une ligne commençant par une lettre minuscule.

Cela devrait donc être:

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

Comment puis-je faire ceci?

Edit: Il y a de très bonnes réponses ici, mais j'ai choisi d'accepter la première qui a fonctionné et qui était la plus ancienne. Merci beaucoup à tous!


la source
1
Latex? Le problème est que vous n'énoncez pas vraiment les règles pour une bonne rupture de phrase. Voulez-vous tout mettre en place et y compris la ponctuation de fin de phrase sur une seule ligne? Mais que se passe-t-il si vous avez une longue phrase et qu'elle s'écoule du bord de votre fenêtre d'affichage?
jamesqf
1
Je me demande ce que vous essayez vraiment de résoudre? Vous devriez peut-être utiliser le formatage de démarque?
Wildcard
@JeffSchaller Merci pour le rappel! J'avais manqué d'une façon ou d'une autre. :)

Réponses:

7

essayer

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

  • $NF !~ /\.$/ faire correspondre la ligne où le dernier élément ne se termine pas par un point,
  • { printf "%s ",$0 imprimer cette ligne avec un espace de fin et sans saut de ligne,
  • next ; } récupérer la ligne suivante,
  • {print;} et l'imprimer.

Je suis sûr qu'il y aura une sedoption.

Remarque: cela fonctionnera avec une ligne se terminant par un point, mais la condition dans les phrases commençant par une lettre majuscule ne sera pas fusionnée. Voir la réponse de Stéphane Chazelas.

Archemar
la source
Si vous aimez intelligent (beaucoup ne le font pas)awk 'ORS=$NF~/\.$/?"\n":" "'
dave_thompson_085
10

Avec awk:

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

Autrement dit, n'ajoutez pas le séparateur d'enregistrement à chaque ligne (ORS vide). Mais ajoutez un séparateur d'enregistrement avant la ligne actuelle si ce n'est pas sur la première ligne et la ligne actuelle ne commence pas par une lettre minuscule. Sinon, ajoutez un espace à la place, sauf sur la première ligne.

Stéphane Chazelas
la source
Lorsque j'exécute cela, certaines paires de mots sont concaténées. Par exemple, And thisone issomehow, broken intomany.je ne sais pas, awkmais faut-il joindre des lignes <space>en plus de RS? Ou est-ce une erreur utilisateur?
B Layer
@BLayer, bien repéré, merci. Devrait être corrigé maintenant.
Stéphane Chazelas
Aucun problème. Bien qu'on se demande d'où viennent les 11 votes positifs. Ça doit être agréable d'avoir des gens qui supposent que vous avez toujours raison. ;)
B Layer
4

En perl:

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

Techniquement, vous vouliez remplacer "nouvelle ligne suivie d'une lettre minuscule" par "espace et cette lettre minuscule", ce que fait le noyau du script perl ci-dessus:

  1. Lisez l'entrée d'une chaîne input.
  2. Mettez à jour la inputvariable pour qu'elle soit le résultat de l'opération de recherche et remplacement.
  3. Imprimez la nouvelle valeur.
Jeff Schaller
la source
1
bon !! traduit en une ligne, perl -0777 -pe 's/\n([a-z])/ $1/g'et peut également être fait avec GNU sed as sed -zE 's/\n([a-z])/ \1/g'(en supposant que l'entrée n'a pas de caractères nuls)
Sundeep
3
@Sundeep, ou perl -Mopen=locale -0777 -pe 's/\n(?=[[:lower:]])/ /g'pour qu'il ne se limite pas aux lettres ASCII.
Stéphane Chazelas
4

Avec, sedvous pouvez utiliser un N;P;Dcycle (afin d'avoir toujours deux lignes dans l'espace de motif et si le premier caractère après la nouvelle ligne est en minuscules, remplacez la nouvelle ligne par un espace) et un test - de cette façon, après chaque ssubstitution, vous redémarrez le cycle:

sed -e :t -e '$!N;/\n[[:lower:]]/s/\n/ /;tt' -e 'P;D' infile
don_crissti
la source
1
Je pense que je vois ce qui se passe ici, mais une réponse élargie aiderait ceux d'entre nous qui n'utilisent pas très souvent les boucles sed et les espaces de motifs.
Joe
@Joe - que voulez-vous dire par «ne pas utiliser l'espace de motif très souvent» ? C'est là que presque toutes les opérations ont lieu - l'espace de stockage est un «espace de stockage» - vous ne pouvez rien faire avec les données pendant qu'elles sont là. Quoi qu'il en soit, j'ai expliqué en détail comment fonctionne un N;P;Dcycle ici, donc je ne reviendrai pas dessus. La différence ici est l' test - pour vérifier si quelque chose a été remplacé ou non - si le test réussit, nous nous branchons en haut du script, sinon cela signifie que rien n'a été remplacé et P;Dest exécuté. Faites-moi savoir si ce n'est toujours pas clair.
don_crissti
3

Utilisation de sedet 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.

Le script sed insère une nouvelle ligne avant chaque ligne commençant par une majuscule (à l'exception de la toute première ligne de saisie). sedLa sortie de est ensuite canalisée fmtpour reformater les paragraphes résultants.

Vous pouvez également l'utiliser parsi vous l'avez installé. C'est un autre reformatage de paragraphe, mais beaucoup plus performant que fmt, avec beaucoup plus de fonctionnalités et d'options.

Notez qu'il y aura une ligne vide entre chaque paragraphe. Les paragraphes doivent être séparés les uns des autres par au moins une ligne vierge. Sans les lignes vides, tout votre échantillon d'entrée est reformaté en un seul paragraphe de plusieurs phrases, par exemple:

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

Si vous devez supprimer les lignes vides après le reformatage, il vous suffit de les rediriger sed- mais cela supprimera TOUTES les lignes vides, y compris celles qui peuvent avoir été dans l'entrée d'origine. par exemple

$ 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
la source
3

Vous pouvez également le faire:

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

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

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

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

la source
2

Python 3

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

C'est le même regex / substitution que la réponse de Jeff

wjandrea
la source