2010-09-17 68 views
2

我有一個文本文件,其中包含幾行,每一行都是逗號分隔的字符串。每一行的格式爲:使用powershell解析逗號分隔文件

<Name, Value, Bitness, OSType>

BitnessOSType是可選的。

例如該文件可以是這樣的:

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

欲每一行解析成4個變量和在其上執行一些操作。這是我使用的PowerShell腳本..但是,我想知道是否可以在PowerShell中使用正則表達式來執行此操作。你能否提供這樣的示例代碼?請注意,每行中的第3個和第4個值可以選擇爲空。

+5

請不要使用正則表達式解析CSV。 :)這是對人類的犯罪。 – Josh 2010-09-17 07:08:48

回答

3

使用Import-Csv能爲您做所有這些(而且更可靠)嗎?

+4

如果你已經有一行CSV文件,你可以將它傳遞給'ConvertFrom-Csv'來將它變成一個對象。這兩個命令都可以讓你指定一個自定義分隔符。 – Josh 2010-09-17 07:06:59

3

正如Tim所建議的那樣,您可以使用Import-Csv。不同之處在於Import-Csv從文件讀取。

@" 
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

您可以用Import-Csv cmdlet的-Header參數指定導入的文件的文件替代的列標題行:

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

比糖蜜慢,但經歷二十年拼湊十幾個或更多後部分解決方案,我決定明確解決它。當然,隨着時間的推移,各種解析器庫現在都可用。


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 
}