【问题标题】:Find if Regex is Not Matched in Powershell在 Powershell 中查找 Regex 是否不匹配
【发布时间】:2017-09-22 21:17:45
【问题描述】:

我有一个 powershell 脚本,用于将包含多个条形码列表(以 6 个数字的字符串格式)和用户信息列表的 word 文档集合中的信息重新排序到一个电子表格和任何具有未知条形码的用户中进入另一个。我想添加一行以将任何没有条形码的用户也包含到未知条形码文件中,因为目前这些用户正在处理中丢失。

我有一个用于挑选条形码的正则表达式,我尝试检查 $matches 变量的 $matches -eq '' 或 $matches -eq $null,它要么不返回任何输出,要么返回表,分别。我还尝试检查我存储条形码的变量是否为 $null 或为空,结果相同。最后,我尝试编写另一个正则表达式来检查条形码输入的格式是否不匹配,该格式返回工作表上的每个用户。

以下是我正在使用的字段及其属性的示例:

#This is the field which would contain barcodes. Note that there are several instances
#of fields with this name in any given sheet. The text is stored in the Result property,
#and for this field it should include a listing of 6-digit numbers possibly including 
#letters to indicate the type of equipment the barcode represents. It will sometimes
#contain notes from whomever filled the sheet in.
Application     : Microsoft.Office.Interop.Word.ApplicationClass
Creator         : **REDACTED**
Parent          : Microsoft.Office.Interop.Word.DocumentClass
Type            : 70
Name            : Text10
EntryMacro      : 
ExitMacro       : 
OwnHelp         : False
OwnStatus       : False
HelpText        : 
StatusText      : 
Enabled         : True
Result          : EQUIPMENT WAS ALREADY MOVED
TextInput       : System.__ComObject
CheckBox        : System.__ComObject
DropDown        : System.__ComObject
Next            : System.__ComObject
Previous        : System.__ComObject
CalculateOnExit : False
Range           : System.__ComObject
------------------------------------------------
Application     : Microsoft.Office.Interop.Word.ApplicationClass
Creator         : **REDACTED**
Parent          : Microsoft.Office.Interop.Word.DocumentClass
Type            : 70
Name            : Text10
EntryMacro      : 
ExitMacro       : 
OwnHelp         : False
OwnStatus       : False
HelpText        : 
StatusText      : 
Enabled         : True
Result          : 
TextInput       : System.__ComObject
CheckBox        : System.__ComObject
DropDown        : System.__ComObject
Next            : System.__ComObject
Previous        : System.__ComObject
CalculateOnExit : False
Range           : System.__ComObject
-----------------------------------------------
Application     : Microsoft.Office.Interop.Word.ApplicationClass
Creator         : **REDACTED**
Parent          : Microsoft.Office.Interop.Word.DocumentClass
Type            : 70
Name            : Text10
EntryMacro      : 
ExitMacro       : 
OwnHelp         : False
OwnStatus       : False
HelpText        : 
StatusText      : 
Enabled         : True
Result          : L 123456, M 654321, 456789, D 987654
TextInput       : System.__ComObject
CheckBox        : System.__ComObject
DropDown        : System.__ComObject
Next            : System.__ComObject
Previous        : System.__ComObject
CalculateOnExit : False
Range           : System.__ComObject

这是我正在使用的代码(除了忽略没有条形码的用户之外,它工作得很好),包括我最近一次失败的挑选这些用户的尝试:

$word = New-Object -ComObject Word.Application
$word.Visible = $false
$word.DisplayAlerts = "wdAlertsNone"
$results = "Header1,Header2,Header3,Header4`n"
$exceptions = "Header2,Header3,Header4`n"
$list = get-childitem 'H:\directory'
foreach($file in $list){
    $path = "H:\directory\$($file.name)"
    $doc = $word.Documents.Open($path)
    $fields = $doc.FormFields
    foreach($field in $fields){
        if ($field.name -eq 'Text2'){
            $ucc = $field.Result.Replace(' / ',",")
            $ucc = $ucc.Replace('/',',')
        }
        elseif($field.name -eq 'Text5'){
            $loc = $field.Result
            }
            $loc = $loc.Trim()
        }
        elseif($field.name -eq 'Text10'){
            if($field.result -like '*UNK*'){
                $exceptions+=$loc + "," + $ucc+"`n"
            }
            #this is where I am storing the barcodes
            $bar = @([regex]::matches($field.Result,'\D*(\d{6})')|%{$_.groups[1].value})
            #this is my attempt at picking out blank codes
            if([regex]::Match($field.result,"*(\d[6])*") -ne $true){
                $exceptions+=$loc + "," + $ucc + "`n"
            }
            foreach($code in $bar){
                $results += $code + "," + $loc + "," + $ucc+"`n"
            }
        }
    }
}
$exceptions | out-file 'H:\directory\exceptions.csv' -Encoding ascii -Force
$results | out-file 'H:\directory\list.csv' -Encoding ascii -Force
$word.quit()
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($word)

【问题讨论】:

  • 请提供示例输入和所需输出以获得完整的minimal reproducible example。也许考虑格式化(例如换行符、段落)以使问题更具可读性。
  • "*(\d[6])*" 看起来像匹配“任意数量的绝对没有(可能是语法错误),然后是任意数量的捕获的数字和 6 组”。正则表达式有什么不寻常的地方吗?

标签: regex powershell powershell-5.0


【解决方案1】:

您可以通过管道传输到ForEach 循环的Where 语句并利用自动变量$Matches 来稍微重构一下。

            $bar = $field.Result | Where{$_ -match '\D*(\d{6})'} | ForEach{$Matches[1].value}
            If(!$bar -eq $null){
                foreach($code in $bar){
                    $results += $code + "," + $loc + "," + $ucc+"`n"
                }
            }Else{
                $exceptions+=$loc + "," + $ucc + "`n"
            }

编辑:我添加了一些对象来模拟您的示例数据,并为每个对象生成一些随机字母用于 $loc$ucc 变量。然后我只是输出到屏幕而不是文件。这是我正在查看的内容:

$letters= 97..123|%{[char]$_}
$fields = @(
    [pscustomobject]@{'Name' = 'Text10';'Result' = @('asdf123456','dasrew345678','fdswer098765')},
    [pscustomobject]@{'Name' = 'Text10';'Result' = 'EQUIPMENT WAS ALREADY MOVED'},
    [pscustomobject]@{'Name' = 'Text10';'Result' = ''}
)
foreach($field in $fields){
    $loc = (Get-Random -Count 5 -InputObject $letters) -join ''
    $ucc = (Get-Random -Count 5 -InputObject $letters) -join ''
    if ($field.name -eq 'Text2'){
        $ucc = $field.Result.Replace(' / ',",")
        $ucc = $ucc.Replace('/',',')
    }
    elseif($field.name -eq 'Text5'){
        $loc = $field.Result
        #}
        $loc = $loc.Trim()
    }
    elseif($field.name -eq 'Text10'){
        if($field.result -like '*UNK*'){
            $exceptions+=$loc + "," + $ucc+"`n"
        }
        $bar = $field.Result | Where{ $_ -match '\D*(\d{6})' } | ForEach {$Matches[1]}
        If(!($bar -eq $null)){
            foreach($code in $bar){
                "results+=$code + `",`" + $loc + `",`" + $ucc"
            }
        }Else{
            "exceptions+=$loc + `",`" + $ucc"
        }
    }
}

输出 5 行。三个用于第一个对象,全部用于同一个“用户”,loc 和 ucc 使用相同的 5 个字符,然后每行一个条形码。然后它为没有条形码的记录再输出 2 行。

results+=123456 + "," + vpsjt + "," + lmsyv
results+=345678 + "," + vpsjt + "," + lmsyv
results+=098765 + "," + vpsjt + "," + lmsyv
exceptions+=hbptn + "," + ugydn
exceptions+=ygbop + "," + zy{mt

【讨论】:

  • 感谢改进的正则表达式,我将在我的代码中使用它。但是,这种循环方式仍然将每个用户和字段作为单独的行返回,无论它们是否有条形码。
  • 当我使用您的示例数据并用它替换脚本中的相关代码时,它会给我想要的结果。
  • 该示例数据的问题在于它是一系列字符串,代表从 powershell 控制台发现的内容。实际数据包括 2-8 个字段,这些字段可能包含也可能不包含条形码,每个都具有相同的名称,超过 20 多个 word 文档。如果不上传 word 文档本身,我无法准确地转录此内容,这有几个原因是不可能的。
  • 因此,每个用户一个文档,并且该文档可以有多个名为“Text10”的字段,这些字段可能有也可能没有条形码。总结一下吗?
  • 好吧,每个用户也可能有多个文档。除此之外,是的。我的工作场所将重复劳动视为一项挑战。
猜你喜欢
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
  • 2018-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
  • 1970-01-01
相关资源
最近更新 更多