使用分号分隔符csv和Powershell

时间:2015-07-06 19:23:27

标签: powershell csv parsing

我必须使用从数据库导出的分隔符​​分号来解析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

3 个答案:

答案 0 :(得分:2)

在这种情况下,您应该使用自定义解析器。您的文件不是有效的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或字符串,则会导致输出错误。主要是,您的示例数据存在问题在<img>标记中,它们不会像XML标准所要求的那样关闭。要解决,请更改它们:<img style="..." src="..." /> - 最后一个斜杠表示立即关闭标记。否则,XML验证将失败,您将无法获得&#34; description&#34;填充。此代码中的XML验证是一种测试,以防有嵌套的起始标记,例如<div>...<div>...</div>...</div>,以便在遇到第一个</div>后,字符串的构建不会停止。

答案 1 :(得分:1)

使用以下脚本将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

enter image description here

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

enter image description here

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

答案 2 :(得分:0)

这可能不是我预期的解决方案,但效果很好,但它比解析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。