PowerShell и Regex: Подробное руководство

Понимание регулярных выражений (regex) может быть головной болью для нас, людей, но regex может быть невероятно мощным способом работы со строками. В этой статье вы узнаете основы работы с PowerShell и Regex.

Вы познакомитесь с полезными командлетами, такими как Select-String, изучите группы захвата regex и получите введение в различные техники разбора regex.

Предварительные требования

  • A Windows 7 or later machine running PowerShell 5.1+. This article will be using PowerShell 7.1.0.

Сопоставление простого текста с Select-String

Чтобы продемонстрировать работу PowerShell и regex вместе, лучше всего пройти через конкретный пример.

Предположим, вы собираете данные с устаревших компьютеров о их аппаратных средствах и, используя утилиту wmic, создаете простой текстовый файл, как показано ниже. Давайте назовем его computername.txt.

BiosCharacteristics={7,11,12,15,16,19,20,21,22,23,24,25,27,30,32,33,39,40,42,43}
 BIOSVersion={"ACRSYS - 2","V1.15","INSYDE Corp. - 59040115"}
 BuildNumber=
 Caption=V1.15
 CodeSet=
 CurrentLanguage=
 Description=V1.15
 EmbeddedControllerMajorVersion=1
 EmbeddedControllerMinorVersion=15
 IdentificationCode=
 InstallableLanguages=
 InstallDate=
 LanguageEdition=
 ListOfLanguages=
 Manufacturer=Insyde Corp.
 Name=V1.15
 OtherTargetOS=
 PrimaryBIOS=TRUE
 ReleaseDate=20200826000000.000000+000
 SerialNumber=NXHHYSA4241943017724S00
 SMBIOSBIOSVersion=V1.15
 SMBIOSMajorVersion=3
 SMBIOSMinorVersion=2
 SMBIOSPresent=TRUE
 SoftwareElementID=V1.15
 SoftwareElementState=3
 Status=OK
 SystemBiosMajorVersion=1
 SystemBiosMinorVersion=15
 TargetOperatingSystem=0
 Version=ACRSYS - 2

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

В этой ситуации Select-String станет вашим новым любимым инструментом.

Select-String – это командлет PowerShell, который позволяет вам указать шаблон регулярного выражения и возвращать строку, соответствующую этому шаблону.

Связанный материал: Как использовать Grep (Select-String) в PowerShell

Поскольку шаблон, который вы ищете, находится в файле, вам сначала нужно прочитать этот файл, а затем найти совпадение с помощью регулярного выражения. Для этого укажите шаблон регулярного выражения с помощью параметра Pattern и путь к текстовому файлу с помощью параметра Path.

Select-String -Pattern "SerialNumber" -Path '.\computername.txt'

Команда Select-String читает файл .\computername.txt и пытается найти набор символов, соответствующий SerialNumber.

PowerShell and Regex : an example output of select-string

Поверьте или нет, вы уже используете регулярные выражения. Регулярное выражение в своей простейшей форме находит совпадение с определенными символами. В данной ситуации вы ищете фразу «SerialNumber» в точности.

Однако, скорее всего, вам не нужна вся строка целиком. Давайте вместо этого начнем создавать сценарий для получения только тех данных, которые вас интересуют.

Вывод команды Select-String представляет собой объект с расширенными возможностями

В предыдущем примере Select-String вернул, как казалось, простую строку, но на самом деле вывод был намного более сложным. Select-String возвращает не только текстовое совпадение. Фактически, эта команда возвращает целый объект.

Например, укажите шаблон регулярного выражения This (is) для поиска в строке This is a string. Как показано ниже, если вы передадите этот вывод в Get-Member, Select-String вернет объект Microsoft.PowerShell.Commands.MatchInfo.

select-string "This (is)" -inputobject "This is a String" | get-member
The properties of a select-string operation

Использование групп захвата

В предыдущем примере обратите внимание на использование регулярного выражения (This (is)). Этот шаблон содержит набор круглых скобок. В регулярном выражении эти скобки создают группу захвата.

Помещая поисковый запрос в скобки, PowerShell создает захватывающую группу. Захватывающие группы “захватывают” содержимое поиска регулярного выражения в переменную.

Обратите внимание на пример выше, Select-String выводит свойство с именем Matches. Это свойство содержит все строки или значения захватывающих групп (если используются скобки) найденных.

Значения всех захватывающих групп находятся в свойстве Matches.Groups. Свойство groups является массивом объектов, внутри которого свойство value содержит фактические данные. Массив groups начинается с 0 (со значением всего соответствия регулярному выражению) и увеличивается с каждой захватывающей группой, указанной в регулярном выражении.

В приведенном выше примере вы можете извлечь как всю строку с помощью свойства matches, так и извлечь совпадение is, которое вы извлекли:

$match = select-string "This (is)" -inputobject "This is a String"
#это свойство будет соответствовать всему значению select-string
$match.Matches.groups[0].value
#это свойство будет соответствовать первой захватывающей группе
$match.Matches.groups[1].value
the output of a capture group

Использование захватывающих групп с шаблонными совпадениями

Захват литеральной строки, например захват литеральной строки is в This is, довольно бессмысленен. Вы не получаете ценных данных, захватывая строку, содержимое которой уже известно. Вы также можете объединить захватывающие группы с шаблонным сопоставлением, чтобы извлечь только интересующую вас информацию.

Сопоставление шаблонов использует специально определенные символы для сопоставления диапазона символов, а не конкретного символа. Можно представить себе сопоставление шаблонов как символ-заместитель * (как в блокноте) на стероидах.

Предположим, вы хотите сопоставить только серийный номер в строке SerialNumber=NXHHYSA4241943017724S00, а не всю строку. Вы хотели бы захватить любой символ после фразы SerialNumber=. Вы можете извлечь этот шаблон с помощью специального символа точки ., за которым следует регулярное выражение символа-заместителя * (называемый квантификатором).

Точка указывает регулярному выражению сопоставить любой отдельный символ после SerialNumber=. * указывает регулярному выражению повторить сопоставление . ноль или более раз. В сочетании с группой захвата регулярное выражение будет выглядеть как SerialNumber=(.*). Вы можете увидеть это ниже:

$string = "SerialNumber=numberwecareabout1042"
#извлечь серийный номер, используя группу захвата
$match = select-string "SerialNumber=(.*)" -inputobject $string
#вывод серийного номера
$match.matches.groups[1].value
Using Capture Groups to extract important information

Специальный символ . – это только одна из множества возможностей сопоставления шаблонов. Можно сопоставлять слова, диапазоны символов, числа и тому подобное. Категория Regex Reference на сайте regexr (через боковую панель) является отличным ресурсом для различных выражений регулярных выражений.

A Practical PowerShell Regex Example

Объединив все вышеперечисленное, давайте создадим скрипт, который:

  1. Вводит список текстовых файлов (в примере вы будете брать только образец текстового файла)
  2. Циклом проходит по текстовым файлам и находит серийный номер, используя SerialNumber=(.*)
  3. Создает хэш-таблицу, которая содержит список имен компьютеров и соответствующих им серийных номеров
#Создаем хэш-таблицу, чтобы хранить серийные номера
$serialNumbers = @{}

#Получаем все текстовые файлы. В данном случае, ограничиваемся одним текстовым файлом
$files = Get-ChildItem "$pwd\computername.txt"

#Заполняем хэш-таблицу
foreach ($file in $files) {
    #Сначала получаем ту же строку, как и в первом примере. На этот раз также сохраняем информацию после метки в группу захвата
    $serialNumber = select-string "SerialNumber=(.*)" $file.FullName
    #Теперь используем группу захвата, чтобы извлечь только серийный номер. Это делается с помощью специального свойства совпадений. Используем также имя файла (без расширения) в качестве индекса для серийного номера
    $serialNumbers[$file.basename] = $serialNumber.matches.groups[1].value
}
#Выводим содержимое хэш-таблицы на экран
$serialNumbers | format-table

Вы можете увидеть приведенный выше сценарий в действии ниже, используя computername.txt:

output of the above code

Оператор Match

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

Один из самых полезных и популярных операторов регулярных выражений в PowerShell – это операторы match и notmatch. Эти операторы позволяют проверить, содержит ли строка определенный шаблон регулярного выражения.

Если строка соответствует шаблону, оператор match вернет значение True. Если нет, то он вернет значение False. Обратное верно для оператора notmatch.

Ниже вы увидите простой пример такого поведения.

#пример использования параметра match
if("my string" -match "string") {
    "string is in my string!"
}

Оператор Split

Если вы хотите разделить строки на непостоянные символы, такие как пробел, запятая или табуляция, вы можете использовать оператор split. Оператор split выполняет сопоставление с регулярным выражением на строке и разбивает строку на одну или несколько строк.

Оператор split “конвертирует” строку в массив строк, разделенных по определенному шаблону регулярного выражения.

#создание массива строк, разделенных символом "\". "\" экранируется внутри split, потому что это специальный символ
"somebody\once told me\the world\is going\to roll me" -split ("\\")

Проверка параметра ValidatePattern

Поддержка регулярных выражений в PowerShell не ограничивается только командлетами и операторами; вы также можете интегрировать проверку сопоставления с регулярным выражением в параметрах.

Связанные: Все, что вы хотели знать о параметрах PowerShell

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

#пример проверки с использованием регулярного выражения. Параметр ValidatePattern в этой функции
#принимает только строчные или заглавные буквы алфавита, а также пробелы.
#символ ^ в начале регулярного выражения обозначает начало строки, а символ $ в конце
#обозначает конец строки (для соответствия *целой* строке). Символ +
#означает, что строка должна содержать один или более символов, чтобы быть принятой
function alphaOnly {
    param([ValidatePattern('^[a-zA-Z ]+$')][string]$alphaCharacters)
    write-output $alphaCharacters
}
#это пройдет проверку
alphaOnly "Hi Mom"
#это не пройдет проверку
alphaOnly "Hi Mom!"

Замена текста с помощью PowerShell и Regex

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

Один из популярных методов замены текста с помощью regex – использование оператора -replace. Оператор -replace принимает два аргумента (разделенных запятой) и позволяет использовать regex для замены строки на другую строку. -replace также поддерживает захватывающие группы, позволяя сопоставить захватывающую группу в поиске и использовать сопоставление в замене.

Например, с помощью -replace вы можете добавить текст к серийному номеру:

$string = "SerialNumber=numberwecareabout1042"
$currentYear = "2020"
#добавить год в конец серийного номера
$serialNumber = $string -replace "SerialNumber=(.*)","SerialNumber=`$1-$currentYear"
write-output $serialNumber
Appending text using the -replace operator and capture groups

Обратите внимание, что в приведенном выше примере символ доллара в $1 экранируется с помощью обратной кавычки. В противном случае PowerShell будет рассматривать $1 как переменную, а не как специальный символ регулярного выражения.

Изучение того, как писать более эффективные регулярные выражения в PowerShell

Все вышеизложенное может показаться сложным, и, ну, так оно и есть. Фактически, существует множество функций регулярных выражений, которые не рассматриваются в приведенном выше примере. К счастью, регулярные выражения широко используются для чтения информации машинами, и существует множество инструментов, которые помогут научиться эффективно использовать регулярные выражения.

  • RegexOne считается основным ресурсом для изучения регулярных выражений. RegexOne представляет возможности регулярных выражений в удобном и интерактивном формате, позволяя вам изучать регулярные выражения в процессе их написания. RegexOne – отличный ресурс для начала изучения работы с регулярными выражениями
  • Regexr – один из лучших инструментов для проверки и создания регулярных выражений. Помимо отличного инструмента для проверки регулярных выражений в режиме реального времени, Regexr также включает шпаргалку и отличный механизм документации.
  • Regexstorm специально использует .Net-движок для работы своего инструмента. На сайте нет всех причиндалов, которые есть на сайтах типа Regexr, но они точно проверят ваше регулярное выражение так же, как это делает PowerShell. Даже если вы используете другие инструменты для создания регулярных выражений, всегда выполняйте регулярное выражение через Regexstorm, чтобы убедиться, что PowerShell будет его правильно разбирать.

Не используйте PowerShell и Regex, если не обязательно!

PowerShell работает с объектами. PowerShell построен на основе структурированных объектов. Работать с объектами, имеющими свойства, намного проще, чем с неструктурированным текстом, где применяется Regex.

Связано: Возвращение к основам: Понимание объектов PowerShell

Одной из основных целей PowerShell и таких структурированных языков, как JSON, является устаревание использования Regex и разбора текста. Человеческий язык великолепно подходит для разбора с помощью Regex, но в целом Regex – это то, что стоит избегать при хранении или передаче данных.

Связано: Управление REST API с помощью PowerShell и JSON

Некоторые люди даже возбуждаются от использования Regex в структурированных языках.

Если вы можете использовать объектно-ориентированный подход или структурированный язык, такой как JSON, XML и т. д., вместо Regex, делайте это! Несмотря на то, что вы можете сделать практически все с помощью Regex, это не означает, что вам следует это делать!

Продолжение работы с Regex

После прочтения этой статьи у вас должно быть базовое представление о том, как Regex помогает машинам разбирать и находить текст, даже при поиске очень конкретных или сложных фраз. У вас также должны быть инструменты для тестирования, проверки и изучения Regex в контексте PowerShell.

Если вы еще не сделали этого, уроки RegexOne – это фантастический следующий шаг. Проверьте свои знания регулярных выражений и улучшите свои навыки работы со строками в PowerShell!

Source:
https://adamtheautomator.com/powershell-regex/