Как и где использовать регулярные выражения Powershell и regex


17 декабря 2019


Использование регулярных выражений в Powershell или regex

Powershell regex - это регулярные выражения с помощью которых можно искать совпадения по всему тексту. Регулярные выражения являются одним из основных инструментов по работе со строками и числами во всех языках. В Powershell достаточно много параметров в которых мы можем использовать шаблоны для поиска. 

Основы

Чаще всего мы ищем данные по его полному или частичному совпадению. Например нам нужно найти элемент массива в котором есть число 1, тогда мы выполним следующее действие:

$users = @('ITSupport',
           'Admin',
           'User1',
           'User 10-10-2018'
          )
$users -like '*1*'

Like в Powershell

Сам параметр Like не относится к регулярным выражениям, но он позволяет искать по маскам (wildcard). Когда мы указываем знак звездочки '*' мы говорим, что в этой части может быть неограниченное количество символов. В нашем случае '*1*' говорит, что слева и справа может находится неограниченное количество символов. Есть еще один параметр в виде знака вопроса '?', который указывает на присутствие одного символа.

Использование этих параметров немного усложнит поиск дат в таком массиве:

$users = @('23-08-2009 Lera',
           'Admin',
           'User1',
           'User 10-10-2018',
           'Elisa 01234-56789',
           'Anton 01-10-1999'
          )
$users -like '*1*'

Like в Powershell

Можно усложнить поиск используя маски и добавив множество условий, но если таких записей будет тысячи у нас наверняка будут ошибки. Для обхода таких ситуаций нужно использовать регулярные выражения. Их особенность в том, что мы можем искать последовательности из разных символов. У нас доступно больше специальных символов чем в масках:

  • \d - обозначает число от 0 до 9;
  • \w - буква или число от 'a' до 'z', от 'A' до 'Z', от 0 до 9 и нижнее подчеркивание '_';
  • \s - пробел, который так же можно указывать как обычный ' ';
  • . - обозначает любой символ кроме новой строки;
  • * - повторение предыдущего элемента ноль или множество раз;
  • + - повторение предыдущего символа 1 или более раз;
  • () - выражение (группировка);
  • ? - ищет наличие или отсутствие предыдущего символа;
  • \ - экранирует любой специальны символ (метасимвол).

Использование любых символов кроме специальных будет соответствовать точному совпадению. Например поиск строк похожих на даты будет выглядеть так:

'\d\d-\d\d-\d\d\d\d'

Далее рассмотрим с помощью каких инструментов и как можно применять regex.

 

Поиск совпадение с шаблоном используя -match

Match основной оператор для поиска по шаблонам. Он возвращает булево значение True если сравнение идет со строками и числами, но если мы используем этот параметр с массивом он вернет каждое значение массива эквивалентное True.

Для примера следующая строка вернет просто True:

'string contain true' -match 'contain'

Match в Powershell

Продолжая прошлый пример мы можем найти все даты с match. Так как мы работаем с массивом у нас вернется не булево True, а значения массива:

$users = @('23-08-2009 Lera',
           'Admin',
           'User1',
           'User 10-10-2018',
           'Elisa 01234-56789',
           'Anton 01-10-1999'
          )
$users -match '\d\d-\d\d-\d\d\d\d'

Match в Powershell с regex

Можно использовать и следующий шаблон, но он может привести к ошибке:

'\w\w-\w\w-\w\w\w\w'

Ошибка может быть там, где в дате случайно стоит буква:

$users -match '\w\w-\w\w-\w\w\w\w'

Match в Powershell с regex

Когда нужно найти все значение в которых отсутствует шаблон - используйте notmatch:

$users -notmatch '\d\d-\d\d-\d\d\d\d'

Match в Powershell с regex

 

Учет регистра

По умолчанию Powershell не чувствителен к регистру, а это значит что все следующие значения будут правдивы:

$array = @('Lera',
           'lera',
           'lerA'
          )
$array -match 'lera'

Match в Powershell с regex и учетом регистра

В большинстве языков у нас вернулось бы только одно значение так как регулярные выражения ассоциируются с учетом регистра. Что бы это исправить это в Powershell есть два варианта. Первый - использование других параметров:

  • cmatch - (case sensitive match) учет регистра;
  • cnotmatch - (case sensitive not match) учет регистра и поиск не совпадающих значений;

Продолжая пример и изменив ключ мы получим верный результат:

$array -cmatch 'lera'

Match в Powershell с regex и учетом регистра

Второй вариант - использование возможностей регулярных выражений, где:

  • '?i' - не учитывает регистр;
  • '?-i' - учитывает регистр.

Отличия от параметра cmatch в том, что он работает с места объявления:

$array -match 'ler(?-i)a'

Учет регистра regex в Powershell

Если использовать ключ исключающий учет регистра с cmatch, то в случае ниже вернуться все значения:

$array -cmatch '(?i)lera'

Отсутствие учета регистра regex в Powershell

 

Замена значений строк и чисел с replace

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

$day = 'Сегодня 25 января'
$day -replace 'января','декабря'

Powershell replace

Более реальный пример - это замена ip адресов или битых ссылок. У нас может быть множество конфигурационных файлов, где используется идентификатор сети, который нужно заменить. Старые идентификаторы сети '192.168.3.0' и '192.178.4.0' и их нужно заменить на '10.10.5.0'. Следующий шаблон может сработать иначе с другими примерами:

$ip = @('IPADDRESS:192.168.3.5',
        'IPADDRESS:192.178.4.7')
$ip -replace '192.\d\d\d.\d','10.10.5'

Powershell replace с regex

Такой шаблон сомнительное решение так как у нас может быть и DNS типа '192.168.5.1' и его не нужно менять. К тому же в начале статьи было написано, что точка в регулярных выражениях обозначает любой символ, а значит следующий пример тоже сработает:

$ip = @('IPADDRESS:192.168.3.5',
        'IPADDRESS:192.178.4.7',
        'IPADDRESS:19211781417')
$ip -replace '192.\d\d\d.\d','10.10.5'

Powershell replace с регулярными выражениями

Экранирование делается через обратный слэш. В этом примере мы сделаем так, что бы у нас искалась именно точка:

$ip -replace '192\.\d\d\d\.\d','10.10.5'

Экранирование в replace Powershell

По аналогии с match у replace тоже есть дополнительный параметр:

  • creplace - замена с учетом регистра.

Часто бывает так, что нужно заменить токи или другой зарезервированный метасимвол. Для успешной замены такие символы нужно экранировать:

$str -replace '\.',' '

Экранирование в регулярных выражениях Powershell

 

Regex и перенос строк

При работе с текстом бывает необходимость добавить строку или убрать ее. Символ обозначающий новую строку в Powershell обозначается "`n". Если вы планируете использовать его в тексте, то он будет работать только при двойных кавычках:

$text = "Перенос `n строки."

Перенос строк в Powershell

Для использования в регулярных выражениях мы так же должны помещать его в двойные кавычки:

$text = "Перенос
строки один. Перенос
строки два."
$text -replace "`n",""

Замена и перенос строк в Powershell

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

$text = "Перенос строки один. Перенос строки два."
$text -replace ". ",".`n"

Экранирование в регулярных выражениях Powershell

$text = "Перенос строки один. Перенос строки два."
$text -replace "\.",".`n"

Экранирование метасимволов в Powershell

 

Экранирование символов

В начале статьи указывалось, что для "экранирования" специальных символов используется знак обратного слыша '\'. Изменив прошлый сценарий добавив слэш мы получим нормальный перенос строк:

$text = "Перенос строки один. Перенос строки два."
$text -replace "\. ",".`n"

Экранирование специальных символов в регулярных выражениях Powershell

Таких символов достаточно много. Например поиск буквы 'd' ненужно экранировать, так как для чисел это уже сделано в виде '\d', а вот круглые скобки да ().

$text = "Expression () digit"
$text -replace "()","неверно"
$text -replace "\(\)","верно"

$text -replace "d","верно d"
$text -replace "\d","неверно d"

Экранирование скобок в Powershell

Весь список, который может понадобится экранировать такой: { } [ ] / \ + * . $ ^ | ?.

 

Определение начала и конца строки с помощью якорей

Иногда нужно найти или отформатировать элементы в начале и конце строки и для их определения есть несколько символов:

  • ^ или \A - определяет начало строки;
  • $ или \Z - обозначают конец строки.

Один из примеров, который вам может пригодиться если вы парсите сайт - это добавление домена и имени протокола к ссылкам:

$urls = @('/pic/fil1.png',
          '/pic/fil2.png')
$urls -replace '^','https://fixmypc.ru'

Начало строки в Powershell

Если вы хотите заменить символ доллара в строке, то его тоже нужно экранировать:

$val = 'Andrey got 100$'
$val -replace '\$',' руб'

Экранирование в Powershell regex

 

Поиск целого и обособленного слова используя шаблоны с boundaries

Я не помню что бы я использовал это на практике, но в Powershell есть возможность искать целое слово по шаблону или его часть. Такая возможность называется границами. 

Представим, что нам нужно найти имя Ян в следующем предложении:

$let = 'Покурил кальян Ян! Яна не захотела.'

Если искать просто 'Ян' - мы получим неверный результат. Мы так же можем не знать, что имя упоминается с восклицательным знаком (мы можем искать это в 100 файлах). Использование точки (обозначает любой следующий символ) тоже никак не поможет:

$let = 'Покурил кальян Ян! Яна не захотела.'
$let -replace 'Ян', 'Саша'
$let -replace 'Ян.', 'Саша'
$let -creplace 'Ян.', 'Саша'

Границы слов в регулярных выражениях Powershell

Избежать таких ситуаций можно поместив слово между метасимволами '\b', которые позволяют искать не часть, а целое слово:

$let = 'Покурил кальян Ян! Яна не захотела.'
$let -replace '\bЯн\b', 'Саша'

Границы слов в регулярных выражениях Powershell

Противоположный вариант, когда мы ищем не отдельное, а часть слова - в таких случаях строка экранируется в '\B'. В отличие от предыдущего случая этот метасимвол ставится там, где мы ожидаем продолжение или окончание слова. Хороший пример это окончания:

$massive = @('Сентябре',
            'Октябре',
            'Ноябрь'
)
$massive -replace '\Bре', 'рь'

Определение начала и конца слова в regex Powershell

Эти метасимволы можно сочетать вместе для того что бы указать, где слово заканчивается и где начинается:

$massive = 'Дули сильные ветер.'
$massive -replace '\Bер\b', 'ра'

Определение начала и конца слова в regex Powershell

 

Поиск совпадений одного из нескольких символов

Когда мы не уверены в конкретном символе - мы можем указать несколько использовав квадратные скобки [] . Значения, которые будут помещены в эти скобки будут соответствовать одному значению:

$services = @('WinRM',
              'WinNT',
              'WinPS')
$services -match 'Win[RP]'

Одна из нескольких букв в Powershell

В примере выше ищутся совпадения либо по букве R или P. Можно указывать диапазон значений. Например такое написание [1-9] говорит, что мы ищем цифры от 1 до 9. Если написать [567-9] у нас будут искаться числа с 5 до 9, затем с 6 по 9 и т.д.

Ниже мы ищем значения, где есть буквы от 'с' до 'я', после которых есть буква 'е'. Во втором примере мы ищем элементы массива, которые начинаются с букв 'д' до 'с':

$month = @('Сентябрь',
           'Октябрь',
           'Декабрь')
$month -match '[с-я]е'
$month -match '^[д-с]'

Одна из нескольких группы выбора в Powershell

Можно использовать любые метасимволы. В примере ниже у нас идет поиск числа или буквы, затем пробела и опять число-буквенное значение:

"100 rub" -match "[\d\w]\s[\w]"

Одна из нескольких группы выбора в Powershell

Вы часто можете увидеть написание похоже на следующее, что обозначает любую букву а A до z, от 0 до 9:

[A-z0-9]

 

Сокращение шаблонов с квантификаторами

В regex есть понятие квантификаторов, который указывает количество повторений символа слева. Квантификаторы помещаются в фигурные скобки {}. В зависимости от ситуации квантификаторы могут работать по разному:

  • {1,3} - значение повторяется от 1 до 3 раз;
  • {2} - значение слева повторяется два раза;
  • {2,} - повторяется минимум 2 раза.

Можно сократить один из шаблонов, который был написан выше до этого:

$users -match '\d{2}-\d{2}-\d{4}'

Квантификаторы в Powershell

Обратите внимание, что в следующем сценарии у нас вернутся все значения т.к. во всех них есть 3 цифры:

$numbers = @('333',
             '4444',
             '55555',
             '666666')
$numbers -match '\d{3}'

Повторение символов в Powershell regex

Кроме квантификаторов вы можете использовать другие метасимволы:

  • + эквивалентен {1,} , что значит повторение более одного раза;
  • * эквивалентно {0,} , повторение неограниченного количества раз;
  • ? тоже что и {0,1} , повторение или отсутствие символа.

 

Создание массива используя split и regex

Иногда нужно преобразовать строку в массив тем самым получить нужные значения. Чаще мы разделяем ее используя запятые или новые строки, как в примере ниже:

$str = 'Lera,Misha,Vasya,Petya'
$str -split ','

split в Powershell

Часто еще применяются другие методы разделения:

  • \s - разделение по пробелам;
  • `n - новая строка.

Если нужен будет учет регистра, то можно использовать creplace.

Когда разделитель указан в качестве точки например (это специальный символ), то его нужно экранировать:

Экранирование в  Powershell

Если вы плохо знаете массивы - рекомендую почитать 'Работа с массивом в Powershell и листами с примерами'.

 

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

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

По шаблону ниже мы ищем значения, где есть от 1 до 3 цифр, пробел после которого идет слово 'rub':

$array = @('Aleksey 1000 rub',
           'Misha 200 usd',
           'Alesya 300 eur',
           'Lera 30 rub')
$array -match '(\d){1,3}\s(rub)'

Группировка в Powershell regex

Если не использовать группировку, то все тоже будет работать, но читаться будет тяжелее:

$array -match '\d{1,3}\srub'

Захват с $Matches

При использовании групп у нас появляется специальная переменная $Matches, которая хранит найденные по шаблонам результаты:

$pay_tax = "В сентябре получил 100 руб. В декабре 200 руб."
$pay_tax -match "(\d\d\d)\sруб"
$Matches

Matches в Powershell

Первая группы, которая попадает в $Matches - это весь шаблон от кавычки до кавычки. Далее идут совпадения, которые находятся в круглых скобках (). Проблема в том, что в $Matches появляется только первый найденный результат и из-за этого значение в '200 руб' у нас не отображается. О том как это исправить будет рассмотрено в следующей главе.

Сам $Matches имеет тип hashtable, который позволяет получать значения по именам:

$matches[0]

Мы можем присвоить свои имена указав свои со следующим синтаксисом:

  • (?<Имя>шаблон)
  • (?'Имя'шаблон)

Если вы планируете использовать вариант с кавычками - не забывайте использовать иные для экранирования всего шаблона:

$pay_tax -match "(?<salary1>\d\d\d)\sруб"
$matches
$pay_tax -match "(?'salary2'\d\d\d)\sруб"
$matches

Именование и группировка в Powershell regex

Когда нужно исключить группу для сохранения в $Matches, можно использовать '?:' :

$pay_tax -match "(?:\d\d\d)\sруб"
$matches

Исключение группы в регулярных выражениях Powershell

Как видно у нас сохранилась только одна общая группа (между кавычками).

Захват всех результатов с Select-String

Для получения всех результатов по шаблону нужно использовать команду Select-String. Продолжая прошлый пример все значения можно увидеть так:

$result = Select-String "\d\d\d\sруб" -InputObject $pay_tax -AllMatches | foreach {$_.matches}
$result.Value

Все Matches используя Select-String Powershell regex

Конечно можно использовать конвейер и обращаться к значениям напрямую:

$result = "В сентябре получил 100 руб. В декабре 200 руб." | Select-String "\d\d\d\sруб" -AllMatches
$result.Matches.Value

Все совпадения используя Select-String Powershell regex 

 

Условия в регулярных выражениях

Представим, что нам нужно найти картинки формата jpg и png используя regex. Использование любых указанных методов описанных выше скорее всего приведет к ошибке так как эта задача нуждается в условиях. Условия в regex обозначаются знаком | где правдиво может быть значение справа или слева. В нашей задаче это будет выглядеть так:

$pics = @('/pic1.jpg',
          '/pic2.png',
          '/doc.docx')
$pics -match '\.(jpg|png)$'

Условия в Powershell regex

Условие выше говорит, что после точки (она экранирована \, так как является специальным символом), строка должна заканчиваться (знак $) на jpg или png. Таких условий может быть много:

$pics -match '\.(jpg|png|docx)$'

Условия в регулярных выражениях Powershell

 

Проверка позиций и зависимостей

Если нужно найти слово рядом с другим, то мы можем это сделать с помощью специальных символов:

  • (?=Слово) - поиск слова слева;
  • (?<=Слово) - поиск слова справа;
  • (?!Слово) - не совпадает со словом слева;
  • (?<!Слово) - не совпадает со словом слева.

Для примера мы знаем, что после слова 'зарплату' будут идти числа и мы хотим узнать их:

$salary = 'вася получил зарплату 100 руб'
$salary -match '?<=зарплату\s(\w+\b)'

Зависимости в регулярных выражениях Powershell

Шаблон выше обозначает:

  • (?<=зарплата) - поиск слова справа от 'зарплата';
  • \s - затем содержится символ пробела;
  • \w+ - содержится число или буква один или множество раз;
  • \b - слово закачивается.

Аналогичное можно сделать и со словом 'руб':

$salary = 'вася получил зарплату 100 руб'
$salary -match '(\d+\s)(?=руб)'

Зависимости в regex Powershell

В этом шаблоне:

  • \d+ - говорит, что у нас есть число повторяющееся один или более раз;
  • \s - после числа следует пробел;
  • (?=руб)  - после пробела находится слово 'руб'.

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

 

Примеры использования в командах и методах Powershell

Особенность Powershell в том, что он нуждается в регулярных выражениях чем другие языки. Используя команды мы и так можем увидеть скалярное (единичное) значение и, если требуется, можем использовать Like и другие варианты для упрощенного определения. Даже используя Invoke-WebRequest мы сразу получаем распарсенные тэги. В Linux ситуация другая - там чаще редактируются конфигурационные файлы и все они имеют разный синтаксис.

Наиболее релевантное использование regex в Powershell - содержимое файлов. Далее рассмотрим все возможности при работе с командами.

Поиск с Where-Object

Условие Where-Object позволяет использовать выражения, что является следствием доступности оператора -match. Можно отфильтровать вывод исключив или включив конкретные значения.

Get-NetIPAddress - возвращает список IP адресов. Если их 100, то вы можете захотеть вернуть только те, где второй октет имеет значения от 160 до 170. Это задача подойдет под регулярные выражения:

Get-NetIPAddress | Where-Object {$PSItem.IPAddress -match '192.1[6-7][0-9]*'}

Получение определенных ip в Powershell regex

Шаблон "192.1[6-7][0-9]*" будет соответствовать следующей логике:

  • Сначала идут цифры 192.1 ;
  • Затем идет цифра с 6 по 7 включительно;
  • Затем с 0 по 9 включительно;
  • после этого повторение предыдущего значения один или множество раз (не обязательно указывать).

Получения результатов поисков по шаблону с Select-String

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

Для примера, если вы являетесь системным администратором, наверняка знаете про файл hosts. В нем по умолчанию находится только один IP '127.0.0.1', а нахождение других должно настораживать. С Select-String мы можем собрать все IP. Самый простой шаблон по поиску IP следующий:

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

Выражение говорит:

  • \d - есть число;
  • {1,3} - оно повторяется от 1 до 3 раз;
  • \. - экранирование специального символа точки, так как октеты адреса разделены ей.

Под это выражение может подходить и адрес типа '666.666.666.666' , но в текущей задаче это не так важно.

# Получение содержимого файла
$file_content = Get-Content -Path 'C:\Windows\System32\drivers\etc\hosts'
# Поиск всех адресов
$result = $file_content | Select-String -Pattern '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' -AllMatches
# Массив со всеми значениями
$result.Matches.Value

Поиск всех совпадений в файле в Powershell

Далее мы можем использовать условие, что бы исключить адрес localhost из выдачи.

Кроме Pattern вы можете использовать NotMatch, который будет искать не совпадающие значения. Использование ключа AllMatches - обязательно, если вы хотите получить не первое попавшееся значение (так работает -match), а все.

Метод .Net и Powershell Replace

У нас доступны две возможности замены значений в строке - первая - эта использование метода .Net:

$name = 'Hi! My name is Alex'
$name.replace('Alex', 'Dima')

Замена строк в Powershell

Он работает быстрее чем следующий вариант, но не позволяет использовать регулярные выражения.

Если вам нужно использовать шаблон - отлично подходит возможность Powershell -replace. У меня есть файл 'host' в корне диска D со следующим содержимым:

8.7.6.5
127.0.0.1
192.168.3.1
192.168.4.5
192.168.5.6

Продолжая одну из предыдущих задач я планирую изменить этот файл, что бы все адреса с сетью '192.168.*' изменились на одну 192.168.100.*:

# Получение содержимого файла
$file_host = Get-Content 'D:\host'
# Изменение значений
$new_host = $file_host -replace '192\.168\.[3-5]', '192.168.100'
# Запись
Set-Content -Path 'D:\host' -Value $new_host
# Вывод
Get-Content 'D:\host'

Замена и запись в файл с регулярными выражениями в Powershell

Регулярное выражение соответствует этой логике:

  • \. - экранирование точки, так как это метасимвол;
  • [3-5] - значения от 3 до 5.

Метод .Net и Powershell split

Split - это преобразование строки в массив

Так же как и в предыдущем случае метод .Net не использует regex и будет работать быстрее:

$t = 'Str1 Str2 Str3'
$t.split(' ')

split в Powershell

Регулярные выражения можно использовать с параметром Powershell -split. На практике я никогда не разделял строки используя что-то кроме точки, запятой или пробела, но в редких случаях это может пригодится.

У нас может быть один текстовый файл следующего формата, который хранит логи:

Log1 10.12.2019 12:12 Error 3 winnt
Log2 11.12.2019 12:15 Error 6 Server 5
Log3 12.12.2019 14:15 Error 3 Zabbix

Нам нужно разделить его и получить только ошибки. Можно сделать это сложно:

$file_log = Get-Content -Path 'D:\log'
$file_log -replace '(Log\d)\s(\d{2})\.(\d{2}).(\d{4})\s(\d{2})\:(\d{2})\s'

Поиск ошибок в Powershell regex 

Где:

  • (Log\d) - говорит, что после слова Log будет одно число. Скобки - это группировка и она не обязательна, но немного повышается читабельность;
  • \s - обозначает пробел;
  • (\d{2}) - число, которое повторяется два раза (день месяца);
  • \. - экранирование точки;
  • (\d{4}) - число повторяющееся 4 раза (год);
  • \: - экранирование двоеточия.

Условия if и switch

Так как match доступен во всех выражениях мы так же можем его использовать в условии if и elseif.  

Для примера у нас есть какая-то программа, которая выводит текст. В этом тексте может содержаться телефон или номер паспорта и мы хотим логировать/выводить предупреждение о доступе к персональным данным:

$text_c = @('Клиент 1 купил продукции на 1000 руб. Его телефон 89920222222',
            'Клиент 2 купил продукции на 800 руб. Его телефон +79920222222'
            'Одобрен кредит Димону по номеру паспорта 4111-44444444'
)
foreach ($text in $text_c){
    if ($text -match '8\d{7}|7\d{7}'){Write-Warning 'Доступ к персональным данным (телефон)'}
    elseif ($text -match '\d{4}\-\d{8}'){Write-Warning 'Доступ к персональным данным (паспорт)'}
}

Условия с Powershell regex

Для реальной задачи, конечно, шаблонов должно быть больше так как телефоны могут содержать и знак '-' или () и т.д.

Разберем следующий шаблон:

'8\d{7}|7\d{7}'

| - этот знак условия (в нашем примере получается условие в условии), которое говорит что совпадение должно быть по левой или правой части. Левая часть начинается с цифры 8 и содержит 7 цифр, а правая начинается с 7 и содержит 7 цифр.

Switch - это такое же условие, в котором не нужно указывать match и if. Добавим еще функционала и теперь персональные данные будут маскироваться:

$text_c = @('Клиент 1 купил продукции на 1000 руб. Его телефон 89920222222',
            'Клиент 2 купил продукции на 800 руб. Его телефон +79920222222',
            'Одобрен кредит Димону по номеру паспорта 4111-44444444',
            'Кто-то купил на 100 руб.'
)
foreach ($text in $text_c){
    switch -regex ($text){
         '8\d{7}' {$text -replace '8\d{5}','8xxxxx'}
         '7\d{7}' {$text -replace '7\d{5}','7xxxxx'}
         '\d{4}\-\d{8}' {$text -replace '\d{4}\-','xxxx-'}
         default {$text}
    }
}

switch в Powershell regex

Как видно, для использования регулярных выражениях в swicth нужно только добавить параметр regex.

Рекомендую почитать статью про Switch в Powershell.

Функции

Для использования шаблонов в расширенных функциях мы можем использовать два метода:

  • ValidatePattern - для проверки только по шаблону;
  • ValidateScript - позволяет использовать скрипт (например тот что выше, со switch).

Их разница так же в том, какая ошибка появится при неверных значениях. Для примера мы можем проверять если в пароле цифры и буквы верхнего регистра:

function Check-Password{
    [cmdletbinding()]
    param(
        [ValidatePattern('(?-i)[A-Z]')]
        [string]
        $pass
        )
}
Check-Password 'pass'
Check-Password 'Pass'

ValidatePattern в Powershell

  • (?-i) - говорит, что следующие значения должны учитываться с регистром;
  • [A-Z] - обозначают буквы с A до Z.

Если переменная не соответствует шаблону, то мы получаем ошибку:

  • Не удается проверить аргумент для параметра "pass". Аргумент "pass" не соответствует шаблону;
  • Cannot validate argument on parameter 'pass'. The argument "pass" does not match.

С ValidateScript можно добавить условия:

function Check-Password{
    [cmdletbinding()]
    param(
        [ValidateScript({
               if ($_ -match '(?-i)[A-Z]' -and $_ -match '\d'){
                   $True
                   }
               else {throw 'Пароль не подходит'}
        })]
        [string]
        $pass
        )
}
Check-Password 'pass'
Check-Password 'Pass1'

ValidateScript в Powershell

Как видно к ошибке добавляется наша собственная надпись:

  • Check-Password : Не удается проверить аргумент для параметра "pass". Пароль не подходит
  • Check-Password : Cannot validate argument on parameter 'pass'. Пароль не подходит

Другие примеры по работам с функциями можно почитать в статье 'Как создавать команды и функции в Powershell вызывать их и передавать параметры'.

Другие методы .Net

Если вам будет удобнее, то вы можете использовать методы .Net для применения шаблонов. Так мы найдем все числа в строке:

$str = ' String 123'
$pattern = [Regex]::new('\d')
$pattern.Matches($str).value

Powershell regex

Все методы по работе с этой функцией можно увидеть так:

[Regex]::new('\d') | Get-Member

 

...

Теги: #powershell #regex


Популярные тэги
О блоге
Этот блог представляет собой конспекты выученного материала, преобретенного опыта и лучшие практики в системном администрировании и программировании.