Regex 仅从文件中筛选大写单词

Regex 仅从文件中筛选大写单词,regex,powershell,foreach,Regex,Powershell,Foreach,我有一个output.txt文件,大约有1000个单词,如下所示: SESSIONDAYOFWEEK FILMTITLELONGALT tblTrans_Ticket. ADMITDETAILSALT2 MESSAGESTUB2ALT3 StartDayOfWeek Description MESSAGESTUB2ALT2 FILMTITLESHORTALT Applications TICKETTYPELONGALT shell一个接一个地解析所有单词,每个单词都会打印我: ForEach-O

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

SESSIONDAYOFWEEK FILMTITLELONGALT tblTrans_Ticket. ADMITDETAILSALT2 MESSAGESTUB2ALT3 StartDayOfWeek Description MESSAGESTUB2ALT2 FILMTITLESHORTALT Applications TICKETTYPELONGALT 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 ForEach对象:无法将输入名称“if”解析为方法。 第1行字符:25 + ... et内容。\out.txt | ForEach对象if($u0.IsUpper){Write Host$0} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CategoryInfo:InvalidArgument:(尾部:PSObject)[ForEach Object],PSArgumentException +FullyQualifiedErrorId:MethodNotFound,Microsoft.PowerShell.Commands.ForEachObjectCommand
我不明白我哪里错了

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

  • -cmatch
    是的区分大小写的变体(其别名为
    -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
开关

请注意,尽管名称不同,PowerShell Core 6.1.0中的
Select String
不支持直接输出匹配的行;相反,它输出匹配信息对象,这些对象的
.Line
属性包含匹配的行,因此需要
选择对象-ExpandProperty Line

建议添加一个新的开关参数以支持匹配字符串的直接输出


至于你所尝试的:

ForEach对象
cmdlet要执行的代码必须作为脚本块传递,即
{…}
中包含的一段代码

您忽略了这一点,这导致了您看到的语法错误

另外,
[string]
类型(一个.NET字符串)没有
.IsUpper()
方法(即使有,您也忘记了
.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的隐式输出行为:只需将
$\uU
作为自己的语句来输出即可-任何既不捕获也不重定向的表达式或命令都会自动输出(发送到成功输出流)


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


[2] 从来没有在PSv4中使用过,但是如果在PSv5+中进行额外的努力,您可以使用它,但关键是
写主机
并不用于输出结果(数据)。

最简单的方法可能是使用regex

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)之间的单个字符

\u
按字面意思匹配字符
\u

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

如果您不想允许带有这些字符的单词通过筛选器,则可以删除
0-9


参见:

你好,弗朗西斯科·曼托瓦尼

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

您可以测试所有大写数组项,因此

$Collection.Where({$_ -ceq $_.ToUpper()})
希望有帮助,

lee

回答得很好,尽管排除带有小写字母的任何内容可能更简单,如
|?{$\u-cnotmatch'[a-z]}
Get-Content .\out.txt | Where-Object { $_ -cmatch "\b[A-Z0-9_]+\b" }
$Collection.Where({$_ -ceq $_.ToUpper()})