搜索字符串中带有特殊字符的子字符串

时间:2019-04-12 13:25:44

标签: powershell substring string-matching

我正在用字符串中的特殊字符搜索子字符串。如何搜索字符串中的子字符串。

$path = 'c:\test'
$mountpoint = 'c:\test\temp\20190987-120\'

我要搜索$path中的$mountpoint

我尝试使用-match-contains-in等。

PS C:\>$path = 'c:\test'
PS C:\>$mountpoint = 'c:\test\temp\20190987-120\'
PS C:\>$path -contains $mountpoint
False

2 个答案:

答案 0 :(得分:1)

在这种情况下,您可以使用-Match

$mountpoint -match [regex]::escape($path)

这里的问题是\字符。它是正则表达式模式中的特殊字符,需要转义。由于-Match运算符会进行正则表达式匹配,因此需要考虑特殊字符。在这种情况下,我选择使用Escape()方法。您可以使用\这样的c:\\test字符分别转义字符。 LotPings条评论重申了这一想法。

使用正则表达式匹配,您可以控制要进行多少匹配。您可以包括锚点和其他特殊字符来定制您的比赛。 Regex101是测试和了解正则表达式的众多在线选项之一。

如果在下面的示例中注意到,匹配项将返回True。这是因为c:\test中存在字符串c:\testing,这可能会给您带来不必要的结果。您需要仔细考虑这些情况。

"c:\testing" -match [regex]::Escape("c:\test")
True

-Contains-in是包含运算符。它们的目的是检查对象值集合中是否存在单个对象值。例如,当您想将单个字符串(如'c:\test'与集合(如'c:\test','c:\folder','c:\folder\test')进行比较时,最好使用它们。它们采用您正在测试的值,并且基本上对集合中的每个项目执行-eq比较(从字面上看,但效率更高)。但是,您可以比较集合,但是整个测试集合必须作为参考集合中的元素存在。使用-Contains时,您希望参考集合位于操作员的LHS上。使用-in,您希望引用集合位于操作员的RHS中。

使用-Co​​ntains和-In

的示例
$collection = 'c:\test','c:\folder','c:\folder\test'
$path = 'c:\test'

$collection -contains $path
True

$path -in $collection
True

"c:\test\" -in $collection
False

请注意最后一个示例中的False返回值,因为结尾的\字符使它与集合中的任何元素都不同。

有关-Match的信息,请参见About_Comparison_Operators,有关Escape()方法的更多详细信息,请参见Regex.Escape Method

答案 1 :(得分:0)

AdminOfThing's answer是有帮助的,但是我发现自己希望事物的框架不同。

  • 您正在寻找一种执行文字子串搜索的方法,该搜索一开始是 ,即<在PowerShell中仅强支持间接 -有关解决方案,请参阅下一部分。

  • 运算符 -contains-in substring 匹配无关(尽管名称相似)在-containsString.Contains() .NET方法之间)。

    • 他们通过元素逐个方式在集合中测试单个值的成员身份(整体上包含 ) -元素平等比较(表示-eq)。有关详细信息,请参见docsthis answer的底部。

    • 如果要组合这两个任务-在集合的所有元素中查找子字符串-您可以利用PowerShell的-match和{{ 1}}运算符-如下所述-也可以在 collection 值的LHS上进行运算,在这种情况下,它们可以充当 filters ;尽管这与测试成员资格并不完全相同,但可以有效地用于此; this answer展示了如何使用-like


解决方案:

使用.NET框架:

.NET String.IndexOf() 方法执行文字子字符串搜索,并返回子字符串在输入字符串中开始的字符的基于-match的索引(和{{1 }}(如果根本找不到子字符串):

0

请注意,与PowerShell的运算符不同,以上默认情况下区分大小写 ,但是您可以使用其他参数更改为不区分大小写的行为:

-1

请注意,PowerShell在许多(但不是全部)上下文中使用不变而不是当前的区域性,例如在运算符 PS> 0 -eq 'foo\bar'.IndexOf('foo\') True PS> 0 -eq 'foo\bar'.IndexOf('FOO\', [System.StringComparison]::InvariantCultureIgnoreCase) True ,{{1}中}和-eq语句。

如果不需要 anchor 您的子字符串搜索,即,如果您只想知道子字符串是否包含在输入字符串的 somewhere 中,则可以使用 String.Contains()

-contains

关于区分大小写的上述几点在这里也适用。


使用-in运算符:

尽管switch隐式执行 substring 匹配,但它是基于 regex regular expression)而不是文字字符串来实现的。< / p>

PS> 'foo\bar'.Contains('oo\') #'# substring is present, but not at the start True 默认执行不区分大小写的 匹配;使用-match变体来区分大小写。

这意味着您可以方便地使用-match(输入的开始锚点)来确保搜索表达式仅在输入字符串的开始处匹配。

相反,为了使您的搜索字符串在正则表达式中被视为 literal 字符串,您必须在其中-match转义任何正则表达式元字符 (具有特殊含义的字符)在正则表达式中。

由于-cmatch本身就是元字符,因此也必须转义,即^

在字符串文字中,您可以手动进行转义:

\

以编程方式,当字符串为变量时,必须使用\方法:

\\

使用# Manual escaping: \ is doubled. # Note the ^ to anchor matching at the start. PS> 'foo\bar' -match '^foo\\' True 运算符:

[regex]::Escape()不同,# Programmatic escaping via [regex]::Escape() # Note the ^ to anchor matching at the start. PS> $s = 'foo\'; 'foo\bar' -match ('^' + [regex]::Escape($s)) True 执行全字符串匹配,并且基于wildcard expressions(在Unix中又称为 glob 世界);尽管与正则表达式关系密切,但它们使用的是更简单,不兼容的语法(功能远不如以前那么强大)。

-like默认执行不区分大小写的 匹配;使用-match变体来区分大小写。

通配符只有3个基本结构,因此也只有3个元字符:-like(匹配单个字符),-like(匹配任意数量的字符,包括一个字符)和{{ 1}}(匹配单个字符的字符集或范围的开始,例如-clike?)。

在最简单的情况下,您只需在搜索字符串后附加*,以查看它是否与输入字符串的开头相符:

[

但是,与[a-z]一样,可能需要以编程方式进行转义,这需要调用[45]

*