PowerShell 文本处理
实例一:求所有电阻值的个数,平均值,总和,最大值,最小值。
问题描述:
有如下一段文本文件,开头有许多描述,字符“~”为有用数据的开始标志,要求:求所有电阻值的个数,平均值,总和,最大值,最小值。
这是一份格式较为规则的文本文件报表。
#文件头有一些无用的描述信息
~
深度 电阻值 放射性值
10 1.5 2.4
20 0.4 1.9
30 2.5 0.5
40 1.3
50 3.1
先不解释,直接贴脚本:
#加载文件,并过滤空行 $fullText=Get-Content .\a.txt | where { !([string]::IsNullOrWhiteSpace($_))} #寻找文件头开始标志 $startFlagIndex=-1 For ($i = 1; $i -lt $fullText.Length; $i++) { if($fullText[$i].Contains("~")) { $startFlagIndex=$i break }
} #去掉文件头 $fullText=$fullText | Select-Object -Skip ($startFlagIndex+1) <# #将文件转换成CSV格式,然后再从CSV转换成对象 #几经周折后,再要深入进行数据处理,将会变得非常方便 #> $objs=$fullText | foreach{ $tokens= $_.Split(' ',[StringSplitOptions]::RemoveEmptyEntries) '"{0}"' -f [string]::Join('","',$tokens) } | ConvertFrom-Csv
#统计放射性值为空的对象 Write-Host "统计放射性值为空的对象" $objs | where { $_.放射性值 -ne $null } | Format-Table -AutoSize
#求所有电阻值的个数,平均值,总和,最大值,最小值 Write-Host "求所有电阻值的个数,平均值,总和,最大值,最小值:" $objs | Measure-Object -Property 电阻值-Average -Sum -Maximum -Minimum |
输出示例:
统计放射性值为空的对象
深度电阻值放射性值
-- --- ----
10 1.5 2.4
20 0.4 1.9
30 2.5 0.5
求所有电阻值的个数,平均值,总和,最大值,最小值:
Count : 5
Average : 1.76
Sum : 8.8
Maximum : 3.1
Minimum : 0.4
Property : 电阻值
回过头再看,脚本完全可以优化为一个foreach循环,每行文本只遍历一次。之所以多次一举,是为了演示分析问题的过程。同样也能得出一个结论,如果可以尽最大可能从数据源拿到CSV文件格式的数据,PowerShell处理起来更方便,一行搞定!
实例二:要求打印出成绩相同的学生及成绩。
问题描述:
给出一段学生成绩文本文件如下:
李一 93
王二 83
王三 93
李四 60
王五 75
马六 61
孙七 75
刘八 75
要求打印出成绩相同的学生及成绩。
李一 93
王三 93
王五 75
孙七 75
刘八 75
问题分析:
第一遍遍历,先须要一张哈希表保存各个成绩的出现的次数。
第二遍遍历,将成绩出现次数大于2的名单打印。
演示脚本:
$scoreTables=@{}
$stus=Get-Content .\ScoresFile.txt |
foreach {
$stu=$_ -split " "
if($scoreTables.ContainsKey($stu[1]))
{
$scoreTables[$stu[1]]++
}
else {
$scoreTables[$stu[1]]=1
}
@{ Score=$stu[1];Name=$stu[0] }
}
$stus | where {
$scoreTables[$_.Score] -gt 1
} | foreach {"{0} {1}" -f $_.Name,$_.Score }
用group-object实现统计,比较完美,稍作整理,也贴在这里:
Get-Content .\a.txt | ForEach-Object {
[PSCustomObject]@{
Name = $_.split()[0]
Value = $_.split()[1]
}
} | Group-Object Value | Where-Object { $_.Count -gt 1 }|
ForEach-Object { $_.Group | ForEach-Object { "{0} {1}" -f $_.name,$_.value } }
#为了和源文件格式保持一直,加入格式化
实例三:将原始文本转换成对象
原始文本:
”data1″:111,”data2″:22,”data3″:3,”data4″:4444444,”data5″:589
要求:转换成对象
$rawTxt='"data1":111,"data2":22,"data3":3,"data4":4444444'
$rawTxt -split ',' | ForEach-Object {
$temp= $_ -split ':'
"{0}={1}" -f $temp[0].Substring(1,$temp[0].Length-2),$temp[1]
} | ConvertFrom-StringData
实例四:提取CSV文件中的域名
有一个CSV文件,其中包含了成千上万的URL链接,每个链接都可能是完整路径包含了文件夹,变量等。希望提取出其中的域名以便于进行深度分析。
我的CSV文件只有一列:
"http://www.pstips.net/diff-with-currentculture-and-currentuiculture.html"
"http://www.pstips.net/tag/powershell-v3"
"http://www.pstips.net/powershell-download-files.html"
"http://www.notelee.com/cs0012-the-type-system-object-is-defined-in-an-assembly-that-is-not-referenced.html"
"http://www.notelee.com/scom-create-wmi-perf-rule.html"
"http://www.lonsoon.com/2013/04/94.html"
"http://www.lonsoon.com/2013/05/101.html"
期望的输出结果:
www.pstips.net
www.pstips.net
www.pstips.net
www.notelee.com
www.notelee.com
www.lonsoon.com
www.lonsoon.com
分析:可以利用Import-csv命令,因为csv文件没有标题,需要临时指定标题。然后利用.NET中的类System.Uri
PS> Import-Csv .\file.csv -Header "link" | foreach { ( [uri]($_.link) ).Host }
参考:
http://www.pstips.net/processing-text-1.html