1
votes

Fractionnement multi-ordre dans Perl

J'ai une chaîne qui provient d'un fichier CSV:

'NA19900,4,111629038,0;0,0;0,"GSA-rs16997168;rs16997168;rs2w34r23424",C,T,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0';

qui devrait être traduit (en quelque sorte) en

my $str = 'NA19900,4,111629038,0;0,0;0,"GSA-rs16997168,rs16997168,rs2w34r23424",C,T,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0';

pour que Le split de perl ne divise pas le champ unique GSA-rs16997168, rs16997168 en deux champs séparés

ie la virgule doit être remplacée par un point-virgule si elle est entre les deux " Je ne trouve pas comment faire cela sur Google

Ce que j'ai essayé jusqu'à présent:

  1. $ str = ~ s / "([^"] +), ([^ "] +)" / "$ 1; $ 2" / g; mais cela échoue avec> 2 expressions

  2. Ce serait génial si je pouvais en quelque sorte dire à la fonction split de Perl de compter tout ce qui se trouve dans "" comme un seul champ même si ce texte a le , délimiteur, mais je ne sais pas comment faire ça :(

  3. J'ai entendu parler des lookaheads, mais je ne vois pas comment je peux les utiliser ici :(


0 commentaires

3 Réponses :


1
votes

Je suppose que nous souhaitons capturer jusqu'à quatre virgules après le dernier ", pour lequel nous commencerions par une expression simple telle que:

use strict;

my $str = 'NA19900,4,111629038,0;0,0;0,"GSA-rs16997168,rs16997168,rs2w34r23424",C,T,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0';
my $regex = qr/(.*",.+?,.+?,.+?,.+?),/mp;

if ( $str =~ /$regex/g ) {
  print "Whole match is ${^MATCH} and its start/end positions can be obtained via \$-[0] and \$+[0]\n";
  # print "Capture Group 1 is $1 and its start/end positions can be obtained via \$-[1] and \$+[1]\n";
  # print "Capture Group 2 is $2 ... and so on\n";
}

# ${^POSTMATCH} and ${^PREMATCH} are also available with the use of '/p'
# Named capture groups can be called via $+{name}

Démo

Test

(.*",.+?,.+?,.+?,.+?),


0 commentaires

9
votes

Pourquoi essayer de recréer un analyseur CSV alors qu'il en existe de parfaits bons?

use Text::CSV_XS qw( );

my $csv = Text::CSV_XS->new({ binary => 1, auto_diag => 2 });
while ( my $row = $csv->get_line($fh) ) {
   $row->[5] =~ s/,/;/g
   $csv->say(\*STDOUT, $row);
}


0 commentaires

1
votes

Pourquoi utiliser un module CSV et une expression régulière.
Utilisez simplement une expression régulière et supprimez le intermédiaire.

$ str = ~ s / (? m: (?:, | ^) "| (?! ^) \ G) [^",] * \ K, (? = [^ "] * ") /; / g;

https: // regex101. com / r / tRDCen / 1

Version Lisez-moi

 (?m:
      (?: , | ^ )
      "
   |  
      (?! ^ )
      \G 
 )
 [^",]* 
 \K 
 ,
 (?= [^"]* " )


0 commentaires