生活如麻 发表于 2018-9-2 12:10:48

21. PowerShell -- 文本处理


[*]  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 { !(::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)
  
  $objs=$fullText | foreach{
  $tokens= $_.Split(' ',::RemoveEmptyEntries)
  '"{0}"' -f ::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))
  {
  $scoreTables[$stu]++
  }
  else {
  $scoreTables[$stu]=1
  }
  @{ Score=$stu;Name=$stu }
  }
  $stus | where {
  $scoreTables[$_.Score] -gt 1
  } | foreach {"{0} {1}" -f $_.Name,$_.Score }
  用group-object实现统计,比较完美,稍作整理,也贴在这里:
  Get-Content .\a.txt | ForEach-Object {
  @{
  Name = $_.split()
  Value = $_.split()
  }
  } | 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.Substring(1,$temp.Length-2),$temp
  } | 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{ ( ($_.link) ).Host }
  参考:
  http://www.pstips.net/processing-text-1.html

页: [1]
查看完整版本: 21. PowerShell -- 文本处理