1
votes

Regex pour supprimer les nouvelles lignes non suivies d'une chaîne spécifique

J'ai un fichier de données délimité avec une entrée utilisateur que je dois nettoyer. Plus précisément:

  1. Il y a des retours à la ligne intégrés dans les champs de texte libre que je souhaite supprimer
  2. Le nombre de colonnes peut changer d'une ligne à l'autre
  3. Le premier champ de chaque ligne DEVRAIT TOUJOURS commencer par le modèle "INC \ d {12}" (les guillemets font partie du modèle). li>
  4. Chaque \ n doit être remplacé par un seul espace s'il n'est pas immédiatement suivi du motif "INC\d{12}"
  5. J'utilise actuellement Perl (de préférence) dans cygwin, mais les réponses awk ou sed sont également acceptables.

Voici quelques données d'entrée simulées (j'ai sauvegardé mon dans un fichier nommé test_input_so.txt):

perl -pe 's/\n(?!"INC\d{12})/ /g;' test_input_so.txt 

Voici la sortie souhaitée pour les données ci-dessus:

"INC000111111111", "field2", "field3"    
"INC000222222222", "field2", "field3","INC000123456789 blahblah"
"INC000444444444", "fie"""ld2", "field3"
"INC000123456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "field3","field4"

J'ai essayé plusieurs combinaisons de lookaheads / backs négatifs, mais je ne sais pas pourquoi cela ne fonctionne pas.

Voici un exemple:

"INC000111111111", "field2", "field3"

"INC000222222222", "field2", "field3","INC000123456789 blahblah"



"INC000444444444", "fie"""ld2", "field3"
"INC000123

456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "fiel
d3","field4"

Il supprime tout \ n , mais supprime incorrectement le \ n suivi de "INC123456789012" qui aurait dû être laissé en place.


0 commentaires

3 Réponses :


2
votes

perl -pe ... fonctionne avec une ligne à la fois, donc une expression régulière multiligne ne vous fera aucun bien.

Le -0 passer en Perl peut changer votre séparateur d'enregistrement d'entrée (ce que Perl notion de ligne est) et vous permet d’opérer sur l’entrée entière sous la forme d’une seule chaîne.

perl -0777 -pe 's/\n(?!"INC\d{12})/ /g;' test_input_so.txt


2 commentaires

il supprime INC000123456789 de la sortie attendue, mais il contredit également l'exigence d'OP "INC \ d {12}"


pourriez-vous s'il vous plaît revoir ma réponse et suggérer des améliorations.



2
votes

Tout d'abord, vous avez des guillemets errants que vous devez corriger pour que vos données puissent être valides au format CSV:

  • ligne 7: "fie" "" ld2 " doit être "fie""ld2"
  • ligne 11: se termine par 2 guillemets doubles

Deuxièmement, ne mettez pas d'espace après la virgule entre les champs: pas a, b mais a,b

Une fois que vous avez réparé ces éléments, vous pouvez utiliser le module Text :: CSV : p >

Ce que je pense que vous voulez vraiment faire, c'est supprimer les nouvelles lignes qui sont à l'intérieur des champs entre guillemets . La structure de ce code est tirée du perldoc Text :: CSV.

"INC000111111111","field2","field3"
"INC000222222222","field2","field3","INC000123456789 blahblah"
"INC000444444444","fie""ld2","field3"
"INC000123456789","field2","field3",""
"INC000333333333","INC000123456789","field3"
"INC000555555555","field2","field3","field4"
perl -MData::Dump=dd -E '
    use Text::CSV;
    my $csv = Text::CSV->new ({ binary => 1, always_quote => 1 })
                   or die "Cannot use CSV: ".Text::CSV->error_diag ();

    my $file = shift @ARGV;
    open my $fh, "<:encoding(utf8)", $file or die;
    while ( my $row = $csv->getline( $fh ) ) {
        my @row = map {s/\n//g; $_} @$row;
        $csv->combine(@row);
        my $line = $csv->string();
        say $line if $line ne q{""};
    }
    $csv->eof or $csv->error_diag();
    close $fh;
' test_input_so.txt


0 commentaires

0
votes

Un autre Perl

$ cat test_input_so.txt
"INC000111111111", "field2", "field3"

"INC000222222222", "field2", "field3","INC000123456789 blahblah"



"INC000444444444", "fie"""ld2", "field3"
"INC000123

456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "fiel
d3","field4"

$

Entrée:

$  perl -0777 -ne ' while( /(^"INC00.+?)(\n"INC.*|\Z)/msg ) { $x=$1;$_=$2; $x=~s/\n//g; print "$x\n" } ' test_input_so.txt
"INC000111111111", "field2", "field3"
"INC000222222222", "field2", "field3","INC000123456789 blahblah"
"INC000444444444", "fie"""ld2", "field3"
"INC000123456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "field3","field4"
$


0 commentaires