计算字符串中的字符,然后使用PowerShell插入分隔符

时间:2012-10-16 11:22:40

标签: powershell

我有一台Linux服务器,它将在一天内生成几个需要插入数据库的文件;使用Putty我可以将它们移到运行SQL 2008的服务器上。问题是文件本身的结构,它有一串文本放在不同的列中,但是sql中的批量插入试图将它全部放入到一列而不是六列。 Powershell可能不是最好的方法,但我在几个网站上看到它如何找到并替换或追加到行的末尾,是否可以计算并插入?

所以文件看起来像这样:'18240087A +17135555555 3333333333',其中18,24,00,87,A是不同的列,然后在A和+之间有一个空格,即字符数10-如图19所示是另一列,则字符20-30是列,字符31-36是新列的空格,依此类推。所以我要插入一个'|'或者','以便sql了解列的结束位置。 PowerShell可以随机计算吗?


这可能不是回应所有回答者的方式,我提前道歉。由于这是我的第一个PowerShell脚本,所以我很感谢你们每个人的意见。这是一个生成CDR记录的Avaya SIP服务器,我必须从服务器提取并插入SQL以便以后报告。导出的文件如下所示:

18/47 10/15

18470214A +14434444444 3013777777 CME-SBC HHHH-CM 4 M00 0

起初我只是想删除第一行并针对输出运行一个脚本,我从Kieranties post修改了该脚本:

$ test = Get-Content C:\ Share \ CDR \ testCDR.txt

$ pattern =“^(。{2})(。{2})(。{1})(。{2})(。{1})(。{1})\ s *(。{ 15})({10})\ S *({7})\ S *({7})\ S *({1})\ S *({1})({1}。 )({1})\ S *(。*)$“

if($ test -match $ pattern){     $ result = $ matches.Values | select -first($ matches.Count-1)

[array]::Reverse($result, 0, $result.Length)

$result = $result -join "|"    
$result | Out-File c:\Share\CDR\results1.txt

}

但后来我意识到我需要第一行,因为它包含日期。我可以尝试以另一种方式解决这个问题。

我现在也看到该文件有时包含2行或更多行的CDR信息,例如:

18/24 10/15

18240087A +14434444444 3013777777 CME-SBC HRSA-CM 4 M00 0

18240096A +14434444445 3013777778 CME-SBC HRSA-CM 4 M00 0

虽然我制作的.ps1文件没有提供第二个字符串,所以我尝试添加:

foreach($ test in $ test) { $ Data = $ Data -split(',')

它无法运行。我怎么能做多行(可能是第一行)?如果您知道可以提供帮助的教程,那也非常受欢迎!

4 个答案:

答案 0 :(得分:1)

PowerShell是我喜欢的一个很棒的工具,它可以做很多事情。我看到您正在使用SQL Server 2008.根据您在服务器上运行的SQL Server版本,它很可能具有SQL Server Integration Services(SSIS),它是一个Extract,Transform和Load(ETL)工具设计帮助在许多场景中迁移数据,例如你的。你在这里描述的文件听起来像一个固定宽度的文件,SSIS可以轻松处理和导入,如果这是一个反复出现的需求(听起来像),SQL Server有很好的方法来自动化负载,包括sftp任务的自动化,甚至将PowerShell脚本作为ETL的一部分运行(我已多次完成)。

如果您的文件确实是固定宽度,并且您希望使用PowerShell将其转换为分隔文件,那么您在答案中使用的正则表达式方法效果很好,或者有几种方法使用System.String方法,例如.insert ()允许您使用行中的字符索引插入分隔符(使用Get-Content读取文件并在每行创建一个String对象,然后使用Foreach循环或Foreach-Object和管道循环它们)。稍微更困难的方法是使用.Substring()方法。您可以使用Substring构建新的String行以提取每个列并使用分隔符连接这些值。对于刚接触PowerShell的人来说,这可能很多,但学习和熟练掌握它的最佳方法之一是练习以多种方式编写相同的脚本。您可以学习可以解决将来可能遇到的其他问题的新技术。

答案 1 :(得分:0)

这是一种方式(非常丑陋的IMO,我认为它可以做得更好):

$a = '18240087A +17135555555 3333333333'
$b = @( ($a[0..1] -join ''), ($a[2..3] -join ''), ($a[4..5] -join ''),
    ($a[6..7] -join ''), ($a[8] -join ''), ($A[10..19] -join ''),
    ($a[20..30] -join ''), ($a[31..36] -join ''))
$c = $b -join '|'
$c
18|24|00|87|A|+171355555|55 33333333|33

我不知道您是否需要进行分割,但更改每个[x..y]中的值可以做更适合您需求的值。请注意,字符数组是从0开始的,那么第一个char是0,依此类推。

答案 2 :(得分:0)

我不太遵循分裂规则。什么样的软件写文本文件呢?也许可以指示改变结构?

话虽如此,使用.Insert()

插入管道很容易
$a= '18240087A +17135555555 3333333333'
$a.Substring(0, $a.IndexOf('+')).Insert(2, '|').insert(5,'|').insert(8, '|').insert(11, '|').insert(13, '|')
# Output: 18|24|00|87|A|

# Rest of the line:
$a.Substring($a.IndexOf('+')+1)
# Output: 17135555555 3333333333

从那里你可以继续分割其余的行数据。

答案 3 :(得分:0)

我根据您的回复改进了我的回答(请注意,您最好更新实际问题以包含该信息!)

Powershell中关于Get-Content的好处是它将内容作为数组拆分返回到行尾字符。结合允许从数组中进行多次分配,最终得到一些简洁的代码。

以下功能可根据您原始答案的修改版本处理每一行。然后它由处理文件的函数包装。

这会读取给定文件,将第一行设置为$date,将其余内容设置为$content。然后创建一个输出文件,将日期添加到输出中,然后循环执行正则表达式检查的其余内容,并在检查成功时添加解析后的内容版本。

Function Parse-CDRFileLine {
    Param(
        [string]$line
    )

    $pattern = "^(.{2})(.{2})(.{1})(.{2})(.{1})(.{1})\s*(.{15})(.{10})\s*(.{7})\s*(.{7})\s*(.{1})\s*(.{1})(.{1})(.{1})\s*(.*)$"
    if($line -match $pattern){ 
        $result = $matches.Values | select -first ($matches.Count-1)
        [array]::Reverse($result, 0, $result.Length)
        $result = $result -join "|"    
        $result
    }
}



Function Parse-CDRFile{
    Param(
        [string]$filepath
    )    

    # Read content, setting first line to $date, the rest to $content
    $date,$content = Get-Content $filepath    

    # Create the output file, overwrite if neccessary
    $outputFile = New-Item "$filepath.out" -ItemType file -Force

    # Add the date line
    Set-Content $outputFile $date

    # Process the rest of the content
    $content | 
        ? { -not([string]::IsNullOrEmpty($_)) } |
        % { Add-Content $outputFile (Parse-CDRFileLine $_) }
}

Parse-CDRFile "C:\input.txt"

我使用了您的示例输入,我得到的结果是:

18:24 10/15
18|24|0|08|7|A|+14434444444 30|13777777 C|ME-SBC |HRSA-CM|4|M|0|0|0
18|24|0|09|6|A|+14434444445 30|13777778 C|ME-SBC |HRSA-CM|4|M|0|0|0

有大量的资源可供使用,但我特别建议的是Douglas Finkes Powershell for Developers它简短,简洁,充满了很好的信息,可以让你用Powershell思考正确的思维方式