我有一个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
我不明白我在哪里错了?
答案 0 :(得分:5)
使用-cmatch
运算符对正则表达式(regular expression)进行区分大小写的匹配:
Get-Content .\out.txt | Where-Object { $_ -cmatch '^\p{Lu}+$' }
-cmatch
是-match
operator的区分大小写的变体(别名为-imatch
);鉴于-match
不区分大小写,因此必须使用-cmatch
来检测区分大小写。
\p{Lu}
匹配一个大写字符-包括重音非ASCII字符,例如Ü
[1] -并且添加+
匹配一个或连续更多。将表达式包含在^
(字符串的开头)和$
(字符串的结尾)中意味着仅匹配完全由大写字符组成的行。
-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
和_
。
答案 2 :(得分:1)
Howdy Francesco Mantovani,
正如其他人所提到的,[string]
类型没有.IsUpper
属性。 [char]
类型具有.IsUpper()
方法 ,但是它也缺少具有该名称的属性。 [咧嘴]
您可以测试所有大写的数组项,从而...
$Collection.Where({$_ -ceq $_.ToUpper()})
希望有帮助,
李