首页 > 解决方案 > 仅过滤文件中的大写单词

问题描述

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

每周会议
电影长篇
tblTrans_Ticket。
承认详情ALT2
MESSAGESTUB2ALT3
StartDayOfWeek
描述
MESSAGESTUB2ALT2
电影短片
应用
门票类型LONGALT

我需要过滤那个文件,只选择只有大写字符的单词,并去掉那些有小写字符的单词。

我在 PowerShell 中运行此命令:

Get-Content .\out.txt | ForEach-Object if ($_.IsUpper) {Write-Host $_}

并且外壳会一一解析所有单词,并且每个单词都会打印出我:

ForEach-Object :输入名称“if”无法解析为方法。
在行:1 字符:25
+ ... 等内容 .\out.txt | ForEach-Object if ($_.IsUpper) {Write-Host $_}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (TAIL:PSObject) [ForEach-Object], PSArgumentException
    + FullyQualifiedErrorId : MethodNotFound,Microsoft.PowerShell.Commands.ForEachObjectCommand

我不明白我哪里错了?

标签: regexpowershellforeach

解决方案


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

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

  • \p{Lu}匹配单个大写字符 - 包括重音的非 ASCII 字符,例如Ü[1] - 并+在一行中添加一个或多个匹配项。将表达式括在^(start of string) 和$(end of string) 中意味着仅匹配完全由大写字符组成的行。

    • 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.
这个 GitHub issue建议添加一个新的 switch 参数来支持匹配字符串的直接输出。


至于你尝试了什么:

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

您忽略了这样做,这导致了您看到的语法错误。

此外,[string]类型(.NET 字符串)没有.IsUpper()方法(即使有,您也忘记了()after .IsUpper)。

只有该[char]类型有一个.IsUpper()方法,即静态方法,您可以按如下方式调用它:[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并不意味着输出结果(数据)。


推荐阅读