поиск подстроки со специальными символами в строке - PullRequest
0 голосов
/ 12 апреля 2019

Я ищу подстроку со специальными символами в строке.Как искать подстроку в строке.

$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 ]

1 голос
/ 12 апреля 2019

Вы можете использовать -Match в данном конкретном случае.

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

Проблема здесь связана с символом \.Это специальный символ в шаблоне регулярных выражений, и его необходимо экранировать.Поскольку оператор -Match выполняет сопоставление с регулярным выражением, необходимо учитывать специальные символы.Я решил использовать метод Escape() для этого сценария.Вы можете экранировать символы индивидуально с помощью символа \, например c:\\test. LotPings комментарии повторяют эту идею.

С сопоставлением с Regex вы можете контролировать, какое сопоставление вы хотите выполнить.Вы можете включить якоря и другие специальные символы, чтобы настроить ваш матч. 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

Notice Falseвернитесь в последнем примере, потому что завершающий символ \ отличает его от любого элемента в коллекции.

Пожалуйста, смотрите About_Comparison_Operators для информации о -Match и смотрите Regex.Метод Escape для более подробной информации о методе Escape().

0 голосов
/ 12 апреля 2019

Ответ AdminOfThing полезен, но я обнаружил, что хочу, чтобы вещи были оформлены по-другому.

  • Вы ищете способ выполнить поиск литералов по подстроке , который привязан в начале , который является косвенно поддерживается в PowerShell - решения см. В следующем разделе.

  • Операторы -contains и -in не связаны с подстрокой , совпадают (несмотря на сходство имен между -contains и String.Contains() .NET метод).

    • Они проверяют членство одного значения (содержится в целом ) в коллекции , поэлементно равенство сравнения (подразумевается -eq). Подробнее см. документы и нижний раздел этого ответа .

    • Если вы хотите объединить две задачи - поиск подстроки во всех элементах коллекции - вы можете воспользоваться тем, что операторы PowerShell -match и -like - обсуждается ниже - может работать и на коллекциях -значных LHS, и в этом случае они действуют как фильтры ; хотя это не совсем то же самое, что тестирование на членство, оно может эффективно использоваться для этого; этот ответ показывает, как использовать -match таким образом.


Решения:

Использование .NET Framework:

.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 использует инвариант , а не текущую культуру во многих (но не во всех) контекстах, таких как операторы -eq, -contains, -in и оператор switch .

Если вам не нужно было привязывать ваш поиск по подстроке, т. Е. Если вы хотите узнать только, содержится ли подстрока где-то во входной строке, вы можете использовать String.Contains()

 PS> 'foo\bar'.Contains('oo\')   #'# substring is present, but not at the start
 True

Приведенные выше замечания о чувствительности к регистру применимы и здесь.


Использование оператора -match:

Хотя -match неявно выполняет сопоставление подстроки , оно основано на регулярном выражении ( регулярное выражение ), а не на буквальной строке.

-match выполняет регистр- нечувствительный сопоставление по умолчанию; используйте вариант -cmatch для чувствительности к регистру.

Это означает, что вы можете удобно использовать ^, привязку начала ввода, чтобы гарантировать, что выражение поиска совпадает только с start входной строки.

И наоборот, для того, чтобы ваша строка поиска рассматривалась как литерал строка в вашем регулярном выражении, вы должны \ -экранировать любое регулярное выражение метасимволы (символы, которые имеют особое значение) в регулярном выражении.

Поскольку \, следовательно, сам является метасимволом, его также следует экранировать, а именно как \\.

В строковых литералах вы можете сделать экранирование вручную:

# 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 выполняет сопоставление полной строки и делает это на основе шаблонных выражений (он же globs в мире Unix); хотя они отдаленно связаны с регулярными выражениями, они используют более простой несовместимый синтаксис (и гораздо менее эффективны).

-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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...