在字符串中搜索具有特殊字符的子字符串[重复]

Posted

技术标签:

【中文标题】在字符串中搜索具有特殊字符的子字符串[重复]【英文标题】:search a substring with special characters in a string [duplicate] 【发布时间】:2019-09-03 06:45:42 【问题描述】:

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

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

我想在$mountpoint中搜索$path

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

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

【问题讨论】:

【参考方案1】:

AdminOfThing's answer 很有帮助,但我发现自己希望以不同的方式构图。

您正在寻找一种方法来执行在开始时锚定文字子字符串搜索,它是唯一的间接在 PowerShell 中得到支持 - 请参阅下一节了解解决方案。

运算符 -contains-in substring 匹配 无关(尽管 -contains 和 @ 之间的名称相似987654322@.NET 方法)。

他们通过逐个元素的方式在集合中测试单个值的成员身份(被作为一个整体包含)平等比较(隐含-eq)。详情请参阅docs 和底部this answer。

如果您想组合这两个任务 - 在集合的所有元素中查找子字符串 - 您可以利用 PowerShell 的 -match-like 运算符这一事实 - 下面将讨论- 也可以对 collection 值的 LHS 进行操作,在这种情况下,它们充当 过滤器;虽然这与成员资格测试并不完全相同,但它可以有效地用于此; this answer 展示了如何以这种方式使用 -match


解决方案:

使用 .NET 框架:

.NET String.IndexOf() 方法执行文字子字符串搜索,并返回输入字符串中子字符串开头的字符的基于0 的索引(如果子字符串不能,则返回-1根本找不到):

 PS> 0 -eq 'foo\bar'.IndexOf('foo\')
 True

请注意,与 PowerShell 的运算符不同,上述操作符默认区分大小写,但您可以通过附加参数更改为不区分大小写的行为:

 PS> 0 -eq 'foo\bar'.IndexOf('FOO\', [System.StringComparison]::InvariantCultureIgnoreCase)
 True

请注意,PowerShell 在许多(但不是全部)上下文中使用 invariant 而不是当前区域性,例如使用运算符 -eq-contains-inswitch声明。

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

 # Substring is present, but not at the start
 # Note: matching is case-SENSITIVE.
 PS> 'foo\bar'.Contains('oo\')   
 True

警告:在 Windows PowerShell 中,.Contains()总是区分大小写。在 PowerShell (Core) 7+ 中,提供了一个不区分大小写的额外重载(例如, 'FOO\BAR'.Contains('oo\', 'InvariantCultureIgnoreCase'))


使用-match 运算符:

虽然-match 确实隐式执行substring 匹配,但它是基于regex (regular expression) 而不是文字字符串。

-match 默认执行大小写-不敏感匹配;使用-cmatch 变体区分大小写。

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

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

由于\ 本身就是一个元字符,它也必须被转义,即\\

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

# 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

使用-like 运算符:

-match 不同,-like 执行 full-string 匹配,并且基于 wildcard expressions(在 Unix 世界中也称为 globs)进行匹配;虽然与正则表达式关系很远,但它们使用更简单、不兼容的语法(并且功能远没有那么强大)。

-like 默认执行大小写-不敏感匹配;使用-clike 变体区分大小写。

通配符只有 3 个基本结构,因此只有 3 个元字符:?(匹配单个字符)、*(匹配任意数量的字符,包括无字符)和 [(开始匹配单个字符的字符集或范围。例如,[a-z][45])。

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

# OK, because 'foo\' contains none of: ? * [
PS> 'foo\bar' -like 'foo\*'
True

# With a variable, using an expandable string:
PS> $s = 'foo\'; 'foo\bar' -like "$s*"
True

不过,与-match 一样,可能需要进行程序转义,这需要调用[WildcardPattern]::Escape()

PS> $s = 'foo['; 'foo[bar' -like ([WildcardPattern]::Escape($s) + '*')
True

【讨论】:

【参考方案2】:

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

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

这里的问题在于\ 字符。它是正则表达式模式中的特殊字符,需要转义。由于-Match 运算符进行正则表达式匹配,因此需要考虑特殊字符。对于这种情况,我选择使用Escape() 方法。您可以使用\ 字符单独转义字符,例如c:\\test。 LotPings cmets 重申这个想法。

使用正则表达式匹配,您可以控制要进行多少匹配。您可以包含锚点和其他特殊字符来定制您的匹配。 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 上。

使用 -Contains 和 -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。

【讨论】:

以上是关于在字符串中搜索具有特殊字符的子字符串[重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 perl 在字符串中搜索特定的子字符串模式

在 CMD 中使用 enabledelayedexpansion 时如何获取具有特殊字符的子字符串?

在字符串数组中搜索子字符串的最有效方法

如何在当前文件夹和所有子文件夹中的所有文件中搜索特定文件内容[重复]

如何在 C# 中搜索字符串数组中的子字符串

Java中最快的子字符串搜索方法是啥