2010-09-17 3 views
2

J'ai un fichier texte qui contient plusieurs lignes, chacune étant une chaîne séparée par des virgules. Le format de chaque ligne est:Analyse d'un fichier séparé par des virgules à l'aide de PowerShell

<Name, Value, Bitness, OSType>

Bitness et OSType sont facultatifs.

Par exemple, le fichier peut ressembler à ceci:

Name1, Value1, X64, Windows7 
Name2, Value2, X86, XP 
Name3, Value3, X64, XP 
Name4, Value3, , Windows7 
Name4, Value3, X64 /*Note that no comma follows X64 */ 
.... 
.... 

Je veux analyser chaque ligne en 4 variables et d'effectuer une opération sur elle. Ceci est le script PowerShell que j'utilise ..

Get-Content $inputFile | ForEach-Object { 
    $Line = $_; 

    $_var = ""; 
    $_val = ""; 
    $_bitness = ""; 
    $_ostype = ""; 

    $envVarArr = $Line.Split(","); 
    For($i=0; $i -lt $envVarArr.Length; $i++) { 
     Switch ($i) { 
      0 {$_var = $envVarArr[$i].Trim();} 
      1 {$_val = $envVarArr[$i].Trim();} 
      2 {$_bitness = $envVarArr[$i].Trim();} 
      3 {$_ostype = $envVarArr[$i].Trim();} 
     }          
    } 
    //perform some operation using the 4 temporary variables 
} 

Cependant, je voulais savoir s'il est possible de le faire en utilisant regex dans PowerShell. Voulez-vous s'il vous plaît fournir un exemple de code pour cela? Notez que les 3ème et 4ème valeurs de chaque ligne peuvent être facultativement vides.

+5

S'il vous plaît ne pas utiliser Regex pour analyser CSV. :) C'est un crime contre l'humanité. – Josh

Répondre

3

Ne serait-il pas préférable d'utiliser Import-Csv qui fait tout cela (et plus fiable) pour vous?

+4

Et si vous avez déjà une ligne de CSV, vous pouvez la convertir en 'ConvertFrom-Csv' pour la transformer en objet. Les deux commandes vous permettent également de spécifier un délimiteur personnalisé. – Josh

3

Comme le suggère Tim, vous pouvez utiliser l'option Import-Csv. La différence est que Import-Csv lit à partir d'un fichier.

@" 
Name1, Value1, X64, Windows7 
Name2, Value2, X86, XP 
Name3, Value3, X64, XP 
Name4, Value3, , Windows7 
Name4, Value3, X64 /*Note that no comma follows X64 */ 
"@ | ConvertFrom-Csv -header var, val, bitness, ostype 

# Result 

var val bitness         ostype 
--- --- -------         ------ 
Name1 Value1 X64          Windows7 
Name2 Value2 X86          XP  
Name3 Value3 X64          XP  
Name4 Value3           Windows7 
Name4 Value3 X64 /*Note that no comma follows X64 */   
6

Vous pouvez spécifier un en-tête de colonne autre ligne pour le fichier de fichier importé avec le paramètre -Header de l'applet de commande Import-Csv:

Import-Csv .\test.txt -Header Col1,Col2,Bitness,OSType 
0

Plus lent que la mélasse, mais après avoir passé 20 ans bricoler une douzaine ou plus solutions partielles j'ai décidé de l'aborder définitivement. Bien sûr, au fil du temps, toutes sortes de bibliothèques d'analyseurs sont maintenant disponibles.


function SplitDelim($Line, $Delim=",", $Default=$Null, $Size=$Null) { 

    # 4956968,"""Visible,"" 4D ""Human"" Torso Anatomy Kit (4-5/8)",FDV-26051,"" ,"",,,,,,a 
    # "4956968,"""Visible,"" 4D ""Human"" Torso Anatomy Kit (4-5/8)",FDV-26051,"" ,"",,,,,,a 
    # ,4956968,"""Visible,"" 4D ""Human"" Torso Anatomy Kit (4-5/8)",FDV-26051,"" ,"",,,,,,a 

    $Field = "" 
    $Fields = @() 
    $Quotes = 0 
    $State = 'INF' # INFIELD, INQFIELD, NOFIELD 
    $NextState = $Null 

    for ($i=0; $i -lt $Line.length; $i++) { 
     $Char = $Line.substring($i,1) 

     if($State -eq 'NOF') { 

      # NOF and Char is Quote 
      # NextState becomes INQ 
      if ($Char -eq '"') { 
       $NextState = 'INQ' 
      } 

      # NOF and Char is Delim 
      # NextState becomes NOF 
      elseif ($Char -eq $Delim) { 
       $NextState = 'NOF' 
       $Char = $Null 
      } 

      # NOF and Char is not Delim, Quote or space 
      # NextState becomes INF 
      elseif ($Char -ne " ") { 
       $NextState = 'INF' 
      } 

     } elseif ($State -eq 'INF') { 

      # INF and Char is Quote 
      # Error 
      if ($Char -eq '"') { 
       return $Null} 

      # INF and Char is Delim 
      # NextState Becomes NOF 
      elseif ($Char -eq $Delim) { 
       $NextState = 'NOF' 
       $Char = $Null 
      } 

     } elseif ($State -eq 'INQ') { 

      # INQ and Char is Delim and consecutive Quotes mod 2 is 0 
      # NextState is NOF 
      if ($Char -eq $Delim -and $Quotes % 2 -eq 0) { 
       $NextState = 'NOF' 
       $Char = $Null 
      } 
     } 

     # Track consecutive quote for purposes of mod 2 logic 
     if ($Char -eq '"') { 
      $Quotes++ 
     } elseif ($NextState -eq 'INQ') { 
      $Quotes = 0 
     } 

     # Normal duty 
     if ($State -ne 'NOF' -or $NextState -ne 'NOF') { 
      $Field += $Char 
     } 

     # Push to $Fields and clear 
     if ($NextState -eq 'NOF') { 
      $Fields += (IfBlank $Field $Default) 
      $Field = '' 
     } 

     if ($NextState) { 
      $State = $NextState 
      $NextState = $Null 
     } 
    } 

    $Fields += (IfNull $Field $Default) 

    while ($Size -and $Fields.count -lt $Size) { 
     $Fields += $Default 
    } 

    return $Fields 
} 
Questions connexes