powershell - 遇到下一条记录时,使用 powershell 脚本读取上一条记录中的所有行
问题描述
我已经用更详细的描述编辑了帖子。我的 Input.DAT 有 3 条记录,每条记录以“01”开头。
01 firstN1 lastN1
02 studentid1 sdf course1
03 class1 dfg location1
05 dfgdf
01 firstN2 lastN2
02 studentid2 ert 568
03 class2 dfg location2
01 firstN3 lastN3
03 class3 dfg location3
我的 Powershellscript.ps1 文件:
foreach-object {
$line = $_.tostring()
$i= $line.substring(0, 2).trim()
if($i -eq "01"){
$firstname=$line.substring(3,7).trim()
$lastname=$line.substring(11,6).trim()}
if($i -eq "02"){
$studentid=$line.substring(3,10).trim()
$course=$line.substring(20,7).trim() }
if($i -eq "03"){
$class=$line.substring(3,6).trim()
$location=$line.substring(14,9).trim()}
if($i -eq "05"){
****************}
# need help in below logic
Foreach ($x in $1) {
if ($x -eq '01') {
add-content -path outputfile.txt -value firstname,"|",$lastname,"|",$studentid,"|",$class,"|",$course,"|",$location
Clear-Variable -Scope Script firstname*, lastname*, studentid*, class*, course* ,location*
我的问题是:当前代码正在寻找第一个“01”并且只读取数据(01 firstN1 lastN1 234)到输出文件。但是我希望编写逻辑来检查循环何时再次命中第二个“01”或/和 $firstname,当我们知道我们已经完成读取第一组记录时,然后只将所有先前的记录读取到输出文件在单行中。
My Output file(outputfile.txt) looks like this.
firstname|lastname|studentid|class|course|location
firstN1|lastN1||||
firstN2|lastN2|studentid1|class1|course1|location1
firstN3|lastN3|studentid2|class2|568|location2
Instead of
firstname|lastname|studentid|class|course|location
firstN1|lastN1|studentid1|class1|course1|location1
firstN2|lastN2|studentid2|class2|568|location2
firstN3|lastN3|studentid3|class3|course3|location3
提前致谢。
解决方案
您的输出似乎不可能,因为您的数据不包含 studentid3 或 class3。
除此之外,我推荐一种不同的方法来提取和输出数据。
为了这个例子,我正在创建一个 3 记录文本文件。
$tempfile = New-TemporaryFile
@'
01 firstN1 lastN1 234
02 studentid1 sdf 345
03 class1 dfg 456
01 firstN2 lastN2 567
02 studentid2 ert 568
03 class2 dfg 890
01 firstN3 lastN3 012
02 studentid3 ert 876
03 class3 dfg 321
'@ | Set-Content $tempfile -Encoding UTF8
如果您知道之后总会有两行,那么您可以使用-Context
参数对Select-String
每 3 行部分进行分组。
Select-String -Path $tempfile -Pattern '01' -Context 0,2
我们只需匹配 01 并选择匹配行和后面的 2 行。context 0,2
现在,如果我们通过循环发送每组行,Foreach-Object
我们就可以操作/解析文本。有几种方法,许多人更喜欢Switch
使用-Regex
参数。我们制作我们的正则表达式模式来获取所需的文本。如您所见,我们将使用两种不同的 switch 语句,一种用于匹配$_.line
,另一种用于$_.Context.PostContext
行。在 switch 语句之后,我们应该填充所有四个变量,因此我们将创建一个PSCustomObject
然后简单地将整个输出通过管道传递到Export-Csv
指定所需的分隔符。
Select-String -Path $tempfile -Pattern '01' -Context 0,2 | ForEach-Object {
Switch -Regex ($_.Line){
'01\s{1,}(.+?)\s{1,}(.+?)\s'{$firstname,$lastname = $matches.1,$matches.2}
}
Switch -Regex ($_.Context.PostContext){
'02\s{1,}(.+?)\s'{$studentid = $matches.1}
'03\s{1,}(.+?)\s'{$classid = $matches.1}
}
[PSCustomObject]@{
FirstName = $firstname
LastName = $lastname
StudentID = $studentid
ClassID = $classid
}
} | Export-Csv -Path outputfile.csv -Delimiter '|' -NoTypeInformation
Csv 格式看起来就像您想要的文本文件,具有列标题的额外好处,并且可以重新导入并用于其他任务。
Get-Content .\outputfile.csv
"FirstName"|"LastName"|"StudentID"|"ClassID"
"firstN1"|"lastN1"|"studentid1"|"class1"
"firstN2"|"lastN2"|"studentid2"|"class2"
"firstN3"|"lastN3"|"studentid3"|"class3"
我只是用Get-Content
. 要使用数据,您应该使用Import-Csv
和处理对象。对象只是使 powershell 如此强大的原因之一。
正则表达式详细信息
01
, 02
, 03
- 文字匹配
\s{1,}
- 一个或多个空格
()
- 捕获组
.+?
- 匹配一个或多个字符,不贪心
\s
- 正好一个空格
编辑
如果像您更新的样本一样,它确实是零星地填充,您很可能最终得到无效数据。第一组会有456的位置,第三组没有学生证。一个更现实的例子肯定会帮助我们帮助你。我不会将其输出到 CSV,因为列不会排列。如果需要,您可以强制使用空白学生 ID,但它似乎更有可能被错误地遗漏了。
$text = @'
01 firstN1 lastN1 234 dfgh
02 studentid1 sdf course1 345
03 class1 dfg 456 35 dfg
05 dfgdf dghfg sdfh 123 45
01 firstN2 lastN2 567
02 studentid2 ert 568
03 class2 dfg location2 890
01 firstN3 lastN3 567
03 class3 dfg location3 890
'@
$text -split '(?=01)' | ForEach-Object {
$ht = [ordered]@{}
Switch -Regex ($_){
'01\s{1,}(.+?)\s{1,}(.+?)\s'{$ht.FirstName,$ht.LastName = $matches.1,$matches.2}
'02\s{1,}(.+?)\s'{$ht.StudentID = $matches.1}
'03\s{1,}(.+?)\s{1,}\w{3,}\s{1,}(.+?)\s'{$ht.ClassID,$ht.LocationID = $matches.1,$matches.2}
}
if($ht.values -ne ''){
[PSCustomObject]$ht
}
}
输出
FirstName : firstN1
LastName : lastN1
StudentID : studentid1
ClassID : class1
LocationID : 456
FirstName : firstN2
LastName : lastN2
StudentID : studentid2
ClassID : class2
LocationID : location2
FirstName : firstN3
LastName : lastN3
ClassID : class3
LocationID : location3
推荐阅读
- react-native - 如何在 react-native-maps 中计算多边形的面积?
- installation - 为什么 BizTalk WCF Lob 适配器 SDK 未安装在 Windows 10 计算机上?
- assembly - 在不检测溢出的 16 位架构中如何存储 32 位字?
- vb.net - 使用异步任务函数处理异常
- hibernate - Fetch Lazy 不适用于具有复合 PK 的 ManyToOne
- vba - 如何使用 Application.ActivateMicrosoftApp xlMicrosoftAccess 打开特定的访问数据库
- react-native - 如何在反应原生 bugsnag 中使用后备组件?
- sql - 计算连接表
- android - 分叉 AOSP 源码
- javascript - 从数组中删除重复项,但使用 JS 忽略一个参数