仅过滤文件中的大写单词

时间:2018-10-04 20:29:00

标签: regex powershell foreach

我有一个output.txt文件,其中包含大约1000个单词,如下所示:

SESSIONDAYOFWEEK
FILMTITLELONGALT
tblTrans_Ticket.
ADMITDETAILSALT2
MESSAGESTUB2ALT3
StartDayOfWeek
Description
MESSAGESTUB2ALT2
FILMTITLESHORTALT
Applications
TICKETTYPELONGALT

我需要过滤该文件,仅选择仅具有大写字母的单词,并去除具有小写字母的单词。

我在PowerShell中运行以下命令:

difftime

shell逐个解析所有单词,每个单词都会显示我:

ForEach-Object : Input name "if" cannot be resolved to a method.
At line:1 char:25
+ ... et-Content .\out.txt | ForEach-Object if ($_.IsUpper) {Write-Host $_}
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (TAIL:PSObject) [ForEach-Object], PSArgumentException
    + FullyQualifiedErrorId : MethodNotFound,Microsoft.PowerShell.Commands.ForEachObjectCommand

我不明白我在哪里错了?

3 个答案:

答案 0 :(得分:5)

使用-cmatch运算符对正则表达式(regular expression)进行区分大小写的匹配:

Get-Content .\out.txt | Where-Object { $_ -cmatch  '^\p{Lu}+$' }
  • -cmatch-match operator的区分大小写的变体(别名为-imatch);鉴于-match不区分大小写,因此必须使用-cmatch来检测区分大小写。

  • \p{Lu}匹配一个大写字符-包括重音非ASCII字符,例如Ü [1] -并且添加+匹配一个或连续更多。将表达式包含在^(字符串的开头)和$(字符串的结尾)中意味着仅匹配完全由大写字符组成的行。

    • Ansgar Wiechers建议使用-cnotmatch '\p{Ll}',它的工作方式略有不同:它将删除包含至少一个小写字母字符的行,这意味着即使行(也)包含非字母字符(只要没有小写字母)。

使用Select-String的替代方法可能会更好:

Select-String -CaseSensitive '^\p{Lu}+$' .\out.txt | Select-Object -ExpandProperty Line

Select-String在默认情况下也不区分大小写(通常是PowerShell),因此此处需要
-CaseSensitive开关。

请注意,尽管名称为Select-String,但从PowerShell Core 6.1.0开始,它不支持直接输出匹配的行;而是输出匹配信息对象,其.Line属性包含匹配的行,因此需要Select-Object -ExpandProperty Line
This GitHub issue建议添加一个新的switch参数以支持直接输出匹配的字符串。


关于您尝试过的事情

要由ForEach-Object cmdlet执行的代码必须作为脚本块传递-即{ ... }中包含的一段代码。

您忽略了此操作,这导致了所看到的语法错误。

此外,[string]类型(.NET字符串)没有.IsUpper()方法(即使这样做,您在()之后忘记了.IsUpper

只有[char]类型具有.IsUpper()方法,即 static 方法,您可以按以下方式调用该方法:[char]::IsUpper('A')-但您必须为输入字符串中的每个字符循环调用此方法:

Get-Content .\out.txt | Where-Object { 
  foreach ($c in $_.ToCharArray()) { if (-not [char]::IsUpper($c)) { return $False } }
  $True
}

最后,不要使用Write-Host返回结果 -Write-Host的打印内容只能显示到控制台-您将无法捕获或重定向此类输出 [2] 。相反,使用Write-Output或更好的是依靠PowerShell的隐式输出行为:仅使用$_作为其自身的语句将输出它-任何表达式或命令都不会捕获或重定向都会自动输出(发送到成功输出流)。


[1]相比之下,使用字符范围表达式[A-Z]将仅识别ASCII范围(英语)的大写字符。

[2]永远不会在PSv4中使用,但是您需要付出额外的努力才能在PSv5 +中使用-但要点是Write-Host并不旨在输出结果 (数据)。

答案 1 :(得分:4)

最简单的方法可能是使用正则表达式。

Get-Content .\out.txt | Where-Object { $_ -cmatch "\b[A-Z0-9_]+\b" }

Where-Object充当过滤器,允许所有匹配项通过并丢弃不匹配项。

-cmatch将进行区分大小写的正则表达式匹配

正则表达式说明:

+量词-在一次和无限次之间进行匹配,并尽可能多地匹配,并根据需要返回(贪婪)

A-Z在A(索引65)和Z(索引90)之间的单个字符

0-9介于0(索引48)和9(索引57)之间的单个字符

_从字面上匹配字符_

\b在单词边界处断言位置

如果您不想让带有这些字符的单词通过过滤器,则可以删除0-9_

请参阅:https://regex101.com/r/CfgEmU/1

答案 2 :(得分:1)

Howdy Francesco Mantovani,

正如其他人所提到的,[string]类型没有.IsUpper属性。 [char]类型具有.IsUpper()方法 ,但是它也缺少具有该名称的属性。 [咧嘴]

您可以测试所有大写的数组项,从而...

$Collection.Where({$_ -ceq $_.ToUpper()})

希望有帮助,