Csv 将制表符分隔符转换为分号

Csv 将制表符分隔符转换为分号,csv,powershell,Csv,Powershell,我已经为我们的T&a系统更新了一个软件,它以制表符分隔的格式生成一个CSV文件。工资单软件需要使用以分号分隔的旧格式。我与这两个供应商都有联系,但其中一个都没有办法容纳另一个,因此我需要转换CSV文件以适应工资单软件。我曾尝试使用PowerShell进行此操作,但结果参差不齐 首先我试过 Import-Csv ".\desktop\new version.csv" -Delimiter `t | Export-Csv ".\converted.csv" -NoTypeInf 它删除了制表符

我已经为我们的T&a系统更新了一个软件,它以制表符分隔的格式生成一个CSV文件。工资单软件需要使用以分号分隔的旧格式。我与这两个供应商都有联系,但其中一个都没有办法容纳另一个,因此我需要转换CSV文件以适应工资单软件。我曾尝试使用PowerShell进行此操作,但结果参差不齐

首先我试过

Import-Csv ".\desktop\new version.csv" -Delimiter `t |
  Export-Csv ".\converted.csv" -NoTypeInf
它删除了制表符分隔符,但没有执行
。于是我就试了

Import-Csv ".\desktop\new version.csv" -Delimiter `t |
  Export-Csv ".\desktop\converted.csv" -NoTypeInformation -Delimiter ";"
将其从选项卡式转换为
,但仅适用于标题。它完全忽略了其余的数据。然后我尝试了另一种方法并使用了

$path = ".\desktop\new.csv"
$outPath = ".\desktop\converted.csv"
Get-Content -path $path |
  ForEach-Object {$_ -replace "`t",";" } |
  Out-File -filepath $outPath

它正确格式化了文件,但在每行数据之间放置了一个额外的空行。我不知道我做错了什么

我使用了一个函数来替换文本文件中的字符串,就像您正在做的那样。这是假设文本文件中除了分隔列的选项卡外,没有其他选项卡。我想没有。您可以这样使用它:

Find-InTextFile -FilePath C:\MyFile.csv -Find "`t" -Replace ';'

function Find-InTextFile
{
    <#
    .SYNOPSIS
        Performs a find (or replace) on a string in a text file or files.
    .EXAMPLE
        PS> Find-InTextFile -FilePath 'C:\MyFile.txt' -Find 'water' -Replace 'wine'

        Replaces all instances of the string 'water' into the string 'wine' in
        'C:\MyFile.txt'.
    .EXAMPLE
        PS> Find-InTextFile -FilePath 'C:\MyFile.txt' -Find 'water'

        Finds all instances of the string 'water' in the file 'C:\MyFile.txt'.
    .PARAMETER FilePath
        The file path of the text file you'd like to perform a find/replace on.
    .PARAMETER Find
        The string you'd like to replace.
    .PARAMETER Replace
        The string you'd like to replace your 'Find' string with.
    .PARAMETER UseRegex
        Use this switch parameter if you're finding strings using regex else the Find string will
        be escaped from regex characters
    .PARAMETER NewFilePath
        If a new file with the replaced the string needs to be created instead of replacing
        the contents of the existing file use this param to create a new file.
    .PARAMETER Force
        If the NewFilePath param is used using this param will overwrite any file that
        exists in NewFilePath.
    #>
    [CmdletBinding(DefaultParameterSetName = 'NewFile')]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateScript({ Test-Path -Path $_ -PathType 'Leaf' })]
        [string[]]$FilePath,

        [Parameter(Mandatory = $true)]
        [string]$Find,

        [Parameter()]
        [string]$Replace,

        [Parameter()]
        [switch]$UseRegex,

        [Parameter(ParameterSetName = 'NewFile')]
        [ValidateScript({ Test-Path -Path ($_ | Split-Path -Parent) -PathType 'Container' })]
        [string]$NewFilePath,

        [Parameter(ParameterSetName = 'NewFile')]
        [switch]$Force
    )
    begin
    {
        if (!$UseRegex.IsPresent)
        {
            $Find = [regex]::Escape($Find)
        }
    }
    process
    {
        try
        {
            foreach ($File in $FilePath)
            {
                if ($Replace)
                {
                    if ($NewFilePath)
                    {
                        if ((Test-Path -Path $NewFilePath -PathType 'Leaf') -and $Force.IsPresent)
                        {
                            Remove-Item -Path $NewFilePath -Force
                            (Get-Content $File) -replace $Find, $Replace | Add-Content -Path $NewFilePath -Force
                        }
                        elseif ((Test-Path -Path $NewFilePath -PathType 'Leaf') -and !$Force.IsPresent)
                        {
                            Write-Warning "The file at '$NewFilePath' already exists and the -Force param was not used"
                        }
                        else
                        {
                            (Get-Content $File) -replace $Find, $Replace | Add-Content -Path $NewFilePath -Force
                        }
                    }
                    else
                    {
                        (Get-Content $File) -replace $Find, $Replace | Add-Content -Path "$File.tmp" -Force
                        Remove-Item -Path $File
                        Rename-Item -Path "$File.tmp" -NewName $File
                    }
                }
                else
                {
                    Select-String -Path $File -Pattern $Find
                }
            }
        }
        catch
        {
            Write-Error -Message $_.Exception.Message
        }
    }
}
Find InTextFile-FilePath C:\MyFile.csv-Find“`t”-Replace';”
函数Find InTextFile
{
查找InTextFile-FilePath“C:\MyFile.txt”-查找“水”-替换“酒”
将字符串“water”的所有实例替换为中的字符串“wine”
“C:\MyFile.txt”。
.举例
PS>Find InTextFile-FilePath'C:\MyFile.txt'-Find'water'
在文件“C:\MyFile.txt”中查找字符串“water”的所有实例。
.参数文件路径
要对其执行查找/替换的文本文件的文件路径。
.参数查找
要替换的字符串。
.参数替换
要将“查找”字符串替换为的字符串。
.参数UseRegex
如果要使用regex查找字符串,请使用此开关参数,否则查找字符串将
从正则表达式字符中转义
.参数NewFilePath
如果新文件已替换,则需要创建字符串,而不是替换
现有文件的内容使用此参数创建新文件。
.参数力
如果使用NewFilePath参数,则使用此参数将覆盖
存在于NewFilePath中。
#>
[CmdletBinding(DefaultParameterSetName='NewFile')]
param(
[参数(必需=$true)]
[ValidateScript({Test Path-Path$\ ux-PathType'Leaf'})]
[string[]]$FilePath,
[参数(必需=$true)]
[字符串]$Find,
[参数()]
[字符串]$Replace,
[参数()]
[开关]$UseRegex,
[参数(ParameterSetName='NewFile')]
[ValidateScript({Test Path-Path($| Split Path-Parent)-PathType'Container}]
[字符串]$NewFilePath,
[参数(ParameterSetName='NewFile')]
[开关]$Force
)
开始
{
如果(!$UseRegex.IsPresent)
{
$Find=[regex]::转义($Find)
}
}
过程
{
尝试
{
foreach($FilePath中的文件)
{
如果($更换)
{
if($NewFilePath)
{
if((测试路径-路径$NewFilePath-路径类型'Leaf')-和$Force.IsPresent)
{
删除项-Path$NewFilePath-Force
(获取内容$File)-replace$Find,$replace | Add Content-Path$NewFilePath-Force
}
elseif((测试路径-路径$NewFilePath-路径类型'Leaf')-和!$Force.IsPresent)
{
写入警告“位于“$NewFilePath”的文件已存在,并且未使用-Force参数”
}
其他的
{
(获取内容$File)-replace$Find,$replace | Add Content-Path$NewFilePath-Force
}
}
其他的
{
(获取内容$File)-替换$Find,$replace |添加内容-路径“$File.tmp”-强制
删除项-路径$File
重命名项-路径“$File.tmp”-新名称$File
}
}
其他的
{
选择字符串-路径$File-模式$Find
}
}
}
抓住
{
写入错误-消息$\异常.Message
}
}
}

我很确定您的上一个示例存在编码问题<代码>获取内容
读取为Ascii,而
输出文件
默认为Unicode。在
输出文件
上设置
-编码
,或者只使用
设置内容

Get-Content -path $path |
ForEach-Object {$_ -replace "`t",";" } |
Set-Content -filepath $outPath
如果需要的话,你甚至可以把它修剪一下

(Get-Content -path $path) -replace "`t",";" | Set-Content -filepath $outPath
然而,您的第二个代码示例

将制表符替换为分号应该可以。如果它不起作用,那么我认为您的源数据有问题


关于源文件

根据注释,上面的代码正在创建一个尾随列。最有可能的原因是正在转换的每一行上的尾随选项卡。如果是这样的话,就需要更多的操作。在这种情况下,更容易使用
foreach
循环

Get-Content -path $path |
ForEach-Object {$_.Trim() -replace "`t",";" } |
Set-Content -filepath $outPath

这将删除每行的最后一个制表符/空白。然而,这样做有一个潜在的巨大警告。我认为,如果末尾有空列,则有可能删除数据。但是,如果这些列已经是空的,那么只要标题的格式正确,并且输入程序可以解释这一点,就不重要了。否则,您将看到使用
Import CSV
读取文件,并删除可以完成的最后一列

你的第二个命令应该可以正常工作
Get-Content -path $path |
ForEach-Object {$_.Trim() -replace "`t",";" } |
Set-Content -filepath $outPath