【问题标题】:How to determine a file is tab delimited in PowerShell?如何确定文件在 PowerShell 中是制表符分隔的?
【发布时间】:2020-09-15 16:22:21
【问题描述】:

我正在编写一个脚本,它读取一些文本文件并将它们转换为 .csv 并更改一些值。我有两个不同的文件源。一个是制表符分隔的 .txt 文件,另一个是逗号分隔的 .txt 文件。有没有办法确定使用哪种类型的分隔符来确定哪种导出函数合适?

get-childitem $workingDir -filter *.txt -Recurse| ForEach-Object {
   
$targetfile = $_.Name
$targetFile = $_.FullName.Substring(0,$_.FullName.Length-4)
$targetFile = $targetfile += ".csv"

if( Get-Content -Delimiter = `t ){
    Write-Host "The file is tab-delimited"
    Get-Content -path $_.FullName 
    ForEach-Object {$_ -replace “`t”,”,” } |  
    Out-File -filepath $targetFile -Encoding utf8 
}

else {
    Write-Host "The file is comma-separated"
    Get-Content -path $_.FullName | 
    Out-File -filepath $targetFile -Encoding utf8 
}
}

【问题讨论】:

  • 阅读第一行并测试它的标签比逗号多:)
  • 可以读取第一行并检查它是否是使用这两种方法的有效对象?可以说逗号分隔的文件不包含任何制表符,反之亦然吗?
  • @mhouston100,您可以从接受的答案中推断逗号分隔的文件确实假定不包含制表符。另一个答案显示如何仅检查第一行。

标签: powershell csv


【解决方案1】:

另一种方法是使用Select-String 检查制表符并设置分隔符。

if(Get-Content $csvfile -First 1 | Select-String -Pattern "`t")
{
    $delim = "`t"
}
else
{
    $delim = ','
}

Import-Csv $csvfile -Delimiter $delim

【讨论】:

  • 这当然是一个简洁的解决方案,您可以使用-Quiet 对其进行改进,它 (a) 在第一次匹配后停止并且 (b) 仅输出 Boolean。但是,如果文件是逗号分隔的,它仍然有些低效,因为没有选项卡然后需要Select-String 仍然读取 整个 文件;仅查看 first 输入行更有效。
【解决方案2】:

假设逗号分隔的文件从不包含制表符(然后是 data),最有效的方法是只检查 first 行每个文件是否存在制表符,使用(Get-Content -First 1 $_.FullName) -match "`t" 最容易做到这一点 - 请参阅Get-Content-matchregular-expression matching operator

# Determine the arguments to pass to Set-Content - later, via splatting - 
# for writing the output file.
$setContentArgs = @{
  LiteralPath = $_.BaseName + '.csv'
  Encoding = 'utf8'
}

# Check the 1st line for containing a tab.
# (This assumes that the comma-separated files contain not tabs as data.)
if ((Get-Content -First 1 $_.FullName) -match "`t") {
  Write-Host "The file is tab-delimited."
  # Read line by line, replace tabs with commas, and write with UTF-8 encoding.
  Get-Content $_.FullName | ForEach-Object { $_ -replace "`t", ',' } |
    Set-Content @setContentArgs
} 
else {
  Write-Host "The file is comma-separated."
  # Just read lines as-is and write with UTF-8 encoding.
  Get-Content $_.FullName |
    Set-Content @setContentArgs
}
  • 注意.BaseName 属性在输入[System.IO.FileInfo] 上的使用,它可以方便地报告文件名没有扩展名,这样您就可以简单地附加新的扩展名。

  • 由于您只处理文本(字符串),因此效率稍高的Set-ContentOut-File 更可取。

  • 关于通过散列表 (@{ ... }) 传递参数的技术,请参阅about_Splatting


如果文件很小(很容易将每个文件作为一个整体(可能两次)放入内存中),您可以通过使用-Raw 读取每个文件作为一个整体显着加快处理速度 并使用
-NoNewLine (PSv5+) 将(可能已修改的)字符串按原样写入输出文件,而不附加尾随换行符。

由于您无论如何都在读取整个文件,因此您可以通过单个 Get-Content 调用并盲目地应用 -replace "`t", ',',因为对于逗号分隔的文件,这将只是一个(快速)无操作。

(Get-Content -Raw $_.FullName) -replace "`t", ',' |
  Set-Content ($_.BaseName + '.csv') -Encoding Utf8 -NoNewLine

【讨论】:

  • 我总是从你的详细帖子中学到一些东西。感谢您分享您的知识!这是 IMO 的最佳答案。
【解决方案3】:

我将为此使用Import-Csv

If(Import-Csv "File path to test if Tab-delimited file" -Delimiter "`t" -Ea SilentlyContinue){
  "File is tab-delimited"
}
If(Import-Csv "File path to test if Comma-CSV file" -Ea SilentlyContinue){
  "File is a comma-separated CSV"
}

【讨论】:

  • 我尝试实现 import-csv 并收到此错误“找不到接受参数“的位置参数”。我在这个测试中尝试的文件是逗号分隔的文本文件。
  • 抱歉,做了您需要的编辑-Ea SilentlyContinue
  • (假设输入文件存在)无论哪种方式都不会出错,因为在没有指定或隐含的分隔符的情况下,PowerShell 只会将文件读取为包含 single 列,跨越 整个 行。换句话说:你的测试不会工作。
猜你喜欢
  • 1970-01-01
  • 2016-06-10
  • 2018-08-20
  • 2019-01-18
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
相关资源
最近更新 更多