Как извлечь значение обратной ссылки / соответствия регулярному выражению в Powershell - PullRequest
19 голосов
/ 05 марта 2009

У меня есть текстовый файл, содержащий строки данных. Я могу использовать следующий скрипт powershell для извлечения интересующих меня строк:

select-string -path *.txt -pattern "subject=([A-Z\.]+),"

Некоторые примеры данных будут:

blah blah subject=THIS.IS.TEST.DATA, blah blah blah

То, что я хочу - это иметь возможность извлекать только фактическое содержимое предмета (то есть строку «THIS.IS.TEST.DATA»). Я попробовал это:

select-string -path *.txt -pattern "subject=([A-Z\.]+)," | %{ $_.Matches[0] }

Но свойство "Matches" всегда равно null. Что я делаю не так?

Ответы [ 8 ]

10 голосов
/ 05 марта 2009

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

$p = "subject=([A-Z\.]+),"
select-string -path *.txt -pattern $p | % {$_ -match $p > $null; $matches[1]}

Редактировать. Пояснения к данту:

-match - оператор сопоставления регулярного выражения:

>"foobar" -match "oo.ar"
True

> $null просто подавляет запись True на выход. (Попробуйте удалить его.) Существует командлет, который делает то же самое, имя которого я не помню в данный момент.

$matches - магическая переменная, в которой хранится результат последней операции -match.

4 голосов
/ 28 января 2010

В PowerShell V2 CTP3 реализовано свойство Matches. Таким образом, будет работать следующее:

select-string -path *.txt -pattern "subject=([A-Z\.]+)," | %{ $_.Matches[0].Groups[1].Value }
3 голосов
/ 05 марта 2009

Еще один вариант

gci *.txt | foreach { [regex]::match($_,'(?<=subject=)([^,]+)').value }
2 голосов
/ 05 марта 2009

Изучив много других ответов, я смог получить то, что хочу, используя следующую строку:

gci *.txt | gc | %{ [regex]::matches($_, "subject=([A-Z\.]+),") } | %{ $_.Groups[1].Value }

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

2 голосов
/ 05 марта 2009

Проблема с кодом, который вы вводите, состоит в том, что строка выбора не передает фактический объект Regex. Вместо этого он передает другой класс с именем MatchInfo, у которого нет фактической информации о совпадениях с регулярным выражением.

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

function Select-Match() {
  param ($pattern = $(throw "Need a pattern"), 
         $filePath = $(throw "Need a file path") )
  foreach ( $cur in (gc $filePath)) { 
    if ( $cur -match $pattern ) { 
      write-output $matches[0];
    }
  }
}

gci *.txt | %{ Select-Match "subject=([A-Z\.]+)," $_.FullName }
1 голос
/ 22 мая 2016

Команда Select-String, похоже, возвращает переменную MatchInfo , а не переменную "string". Я потратил несколько часов, чтобы найти это на форумах и на официальном сайте, но не повезло. Я все еще собираю информацию. Обойти это можно, объявив явным образом строковую переменную для хранения результата, возвращенного из строки выбора, из вашего примера:

[string] $ foo = select-string -path * .txt -pattern "subject = ([A-Z.] +),"

Переменная $ foo теперь является строкой, а не объектом MatchInfo.

Надеюсь, это поможет.

PS5 PowerShell версии 5 манипуляции со строками

1 голос
/ 05 марта 2009

См. Эти примечания по Регулярные выражения в PowerShell

0 голосов
/ 28 января 2010

Другой вариант, соответствующий 7 цифрам в строке

echo "123456789 hello test" | % {$_ -match "\d{7}" > $null; $matches[0]}

возвращает: 1234567

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