【问题标题】:Using semicolon separator csv with Powershell在 Powershell 中使用分号分隔符 csv
【发布时间】:2015-09-24 01:54:05
【问题描述】:

我必须使用从数据库导出的分隔符​​分号解析 CSV 文件。简单的

$csv = import-csv -Path C:\Users\user\Desktop\bla\file.csv -Delimiter ';'
foreach ($line in $csv) {     
  $field = $line -split ';'  
  echo $field[3]
}

效果不佳,因为在其中一列中,我有必须使用的示例 HTML 代码。字段以;<div> 开头,以</div>; 结尾。标签之间我有带有样式属性的标签,所以有很多分号。有人知道如何用文本修复或解析文件吗?

几行 CSV 文件

product_code;active;name;price;vat;unit;category;producer;other_price;weight;description;stock;stock_warnlevel;availability;delivery;views;rank;rank_votes;images 1;images 2;images 3;images 4;images 5;images 6
raz;1;nazwa pierwszego;19.95;23%;szt.;kategoria;producent1;;1;<div style="background-color:#fff;min-width:640px;max-width:980px;margin:0 auto;padding: 30px"><table style="width:100%;" class="mceItemTable"><tbody><tr><td style="width:50%;"><p style="text-align:;font:16px arial;color:;margin:1em 0;">sometext</p></td><td style="width:50%;"><img style="width:100%;max-width:600px;display:block;margin:0 auto;" src="http://domain.tld/image.png"></td></tr></tbody></table></div>;;1;auto;48 godzin;0;0;0;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg
dwa;1;nazwa drugiego;25.95;23%;szt.;kategoria;producent2;;1;<div style="background-color:#fff;min-width:640px;max-width:980px;margin:0 auto;padding: 30px"><table style="width:100%;" class="mceItemTable"><tbody><tr><td style="width:50%;"><p style="text-align:;font:16px arial;color:;margin:1em 0;">sometext</p></td><td style="width:50%;"><img style="width:100%;max-width:600px;display:block;margin:0 auto;" src="http://domain.tld/image.png"></td></tr></tbody></table></div>;12.0000;1;auto;48 godzin;0;0;0;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg
trzy;1;nazwa trzeciego;29.95;23%;szt.;kategoria;producent1;;1;<div style="background-color:#fff;min-width:640px;max-width:980px;margin:0 auto;padding: 30px"><table style="width:100%;" class="mceItemTable"><tbody><tr><td style="width:50%;"><p style="text-align:;font:16px arial;color:;margin:1em 0;">sometext</p></td><td style="width:50%;"><img style="width:100%;max-width:600px;display:block;margin:0 auto;" src="http://domain.tld/image.png"></td></tr></tbody></table></div>;1.0000;1;auto;48 godzin;0;0;0;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg
cztery;1;nazwa czwartego;3.95;23%;szt.;kategoria;producent2;;1;<div style="background-color:#fff;min-width:640px;max-width:980px;margin:0 auto;padding: 30px"><table style="width:100%;" class="mceItemTable"><tbody><tr><td style="width:50%;"><p style="text-align:;font:16px arial;color:;margin:1em 0;">sometext</p></td><td style="width:50%;"><img style="width:100%;max-width:600px;display:block;margin:0 auto;" src="http://domain.tld/image.png"></td></tr></tbody></table></div>;2.0000;1;auto;48 godzin;0;0;0;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg;http://domain.tld/image.jpg

【问题讨论】:

  • 你能从 csv 中添加几行吗?
  • 格式化后,该文件无法正常工作。如果没有文本限定符,您将无法可靠地区分用作字段之间分隔符的分号与字段中的部分内容之间的区别。使用不同的分隔符,或使用文本限定符(通常是引号)以便区分它们。
  • 带有描述的列将始终以&lt;div 开头并以&lt;/div&gt; 结尾正则表达式不起作用?
  • @tomipnh 是的,正则表达式不应该也能正常工作,你可能在生产中嵌套了​​ div - 惊喜。只有 HTML/XML 验证可以提供帮助。我给你一个。

标签: powershell csv parsing


【解决方案1】:

在这种情况下,您应该使用自定义解析器。您的文件不是有效的 CSV,因为它没有包裹数据的字符串分隔符(虽然很难正确包裹 HTML,但您可以先对其进行 HTML 转义,然后用引号包裹,然后用逗号/分号分隔)。如果您自己创建这样的文件,请考虑使用 [System.Web.HttpUtility]::HtmlEncode() 执行 HTML 字符的转义。如果没有,并且您需要解析此文件,您将需要加入被分号错误分割的字符串部分 - 但当然,对Import-CSV 的原始调用将不起作用,您必须模拟它功能。

function Import-XMLCSV {
    Param($text,[char]$delimiter=',')
    $columns, $splitText=$text.split("`r`n") # we need lines, not full string
    # also this neat trick splits first line off the rest of text
    $columns= $columns.split($delimiter) 
    $splitText | foreach {
        $splits=@{}
        $splitLine=$_.split($delimiter) # split line normally
        $index=0
        $propIndex=0
        $value=""
        $tag=""
        while ($index -lt $splitLine.length) {
            if ($value -ne "") { $value+=$delimiter }
            if ($splitLine[$index] -match "^<([a-zA-Z0-9]+)") { $tag = $matches[1] }
            $value+=$splitLine[$index]
            if ($tag -eq "") {
                # no tag found, put full string in this property
                $splits[$columns[$propIndex]]=$value
                $value=""
                $propIndex+=1
            } else {
                if ($splitLine[$index] -match "/${tag}") {
                    # if there's a corresponding tag in this piece
                    # check valid XML in here, if not, continue
                    try {
                        $xml = New-Object System.Xml.XmlDocument
                        $xml.LoadXml($value)
                        # throws exception if not a valid XML, so won't save if unpaired
                        $splits[$columns[$propIndex]]=$value
                        $value=""
                        $propIndex+=1
                        $tag=""
                    }
                    catch [System.Xml.XmlException] {
                        # no action
                        write-debug "$index $propIndex $tag $value"
                        write-debug $_.exception
                    }
                } # if matches /tag
            } # if not matches /tag, continue adding to $value
            $index+=1
        } # end while
        # past this, we've got hash table populated
        New-Object PSCustomObject -Property $splits # return prepared object
    } # end foreach splittext
}

此代码有限制(见下文)。

但请注意,如果您的任何一个字段中都没有有效的 XML 或字符串,则会导致错误的输出。首先,您的示例数据的问题在于您的 &lt;img&gt; 标记,它们没有按照 XML 标准的要求关闭。要解决此问题,请将它们更改为:&lt;img style="..." src="..." /&gt; - 最后一个斜杠表示立即关闭标签。否则 XML 验证失败,您不会得到“描述”。这段代码中的 XML 验证是一个测试,以防有嵌套的起始标签,比如 &lt;div&gt;...&lt;div&gt;...&lt;/div&gt;...&lt;/div&gt;,这样在遇到第一个 &lt;/div&gt; 后,字符串的构建就不会停止。

【讨论】:

    【解决方案2】:

    这可能不是我预期的解决方案,但效果很好,但比解析 Xml 的解决方案要容易得多。

    $strPath="C:\Users\user\Desktop\bla\file.csv"
    $objExcel=New-Object -ComObject Excel.Application
    $objExcel.Visible=$false
    $workbook=$objExcel.Workbooks.Open($strPath)
    $worksheet = $workbook.sheets.item("file")
    Write-Host $worksheet.Range("K3").Text
    $objexcel.quit()
    

    工作需要 Microsoft Excel。

    【讨论】:

      【解决方案3】:

      使用以下脚本将comma/semi-column/pipe 分隔值或任何其他符号分隔值转换为 Excel 中的不同列。将此保存为.ps1 文件。

      $executingPath = split-path -parent $MyInvocation.MyCommand.Definition
      $inputCSV = $executingPath + "\InputFileName.txt"
      $outputXLSX = $executingPath + "\Output.xlsx"
      $excel = New-Object -ComObject excel.application 
      $workbook = $excel.Workbooks.Add(1)
      $worksheet = $workbook.worksheets.Item(1)
      $TxtConnector = ("TEXT;" + $inputCSV)
      $Connector = $worksheet.QueryTables.add($TxtConnector,$worksheet.Range("A1"))
      $query = $worksheet.QueryTables.item($Connector.name)
      $query.TextFileOtherDelimiter = $Excel.Application.International(5)
      $query.TextFileParseType  = 1
      $query.TextFileColumnDataTypes = ,2 * $worksheet.Cells.Columns.Count
      $query.AdjustColumnWidth = 1
      $query.Refresh()
      $query.Delete()
      $Workbook.SaveAs($outputXLSX,51)
      $excel.Quit()
      

      将输入文件放置在脚本文件所在的位置并运行脚本。输出的 excel 文件将在同一位置生成。



      默认情况下,Windows 会根据区域设置默认分隔符。例如,它可能是 逗号 作为默认分隔符。如果您想更改为半列,请按照以下步骤操作。



      转到Control Panel 并单击Region and Language。将打开一个窗口。点击Additional Settings

      现在将打开另一个窗口。将List Separator 部分中的符号更改为所需的符号(例如半列),然后单击应用。

      运行脚本。它将创建一个excel文件,excel文件中的列将在半列的基础上生成。

      【讨论】:

      • 你也可以只设置$query.TextFileOtherDelimiter = ';'
      猜你喜欢
      • 2015-11-25
      • 2012-08-30
      • 2019-01-07
      • 2020-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-27
      • 1970-01-01
      相关资源
      最近更新 更多