使用 Powershell 和分号作为分隔符的 CSV 文件

4

我需要解析从数据库导出的以分号为分隔符的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>;结尾;在标签之间,我有带有style属性的标签,因此有很多分号。有没有什么想法可以修复或解析包含文本的文件?

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

1
你能从CSV文件中添加几行吗? - Avshalom
按照格式排版后,该文件无法正常工作。如果没有文本限定符,您无法可靠地区分用作字段分隔符的分号和位于字段内部的内容的一部分。请使用不同的分隔符或使用文本限定符(通常是引号)以便它们可以被区分开来。 - alroc
列描述始终以<div开头,以</div>结尾,正则表达式无法工作? - tomipnh
@tomipnh 是的,正则表达式可能也行不通,你的生产环境中可能有嵌套的div - 惊喜惊喜。只有HTML/XML验证才能帮助解决问题。我已经为您找到了一个。 - Vesper
3个回答

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验证会失败,并且您不会得到填充“description”的结果。此代码中的XML验证是一项测试,以防嵌套起始标签,例如<div>...<div>...</div>...</div>,因此在遇到第一个</div>之后,字符串的构建不会停止。

1
使用以下脚本将以逗号/分号/管道符或任何其他符号分隔的值转换为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会根据地区设置一个默认分隔符。例如,默认分隔符可能是逗号。如果您想更改为分号,请按照以下步骤操作。
转到控制面板,然后单击区域和语言。一个窗口会打开。单击其他设置

enter image description here

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

enter image description here

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

你也可以直接设置 $query.TextFileOtherDelimiter = ';' - craig

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。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接