Извлекать (повторять) группы, содержащие скобки, используя регулярные выражения - PullRequest
0 голосов
/ 04 декабря 2018

Моя строка:

(01) this is value one (02) and this is 2 (03) and this is number 3

Желаемый результат (пара ключ / значение):

(01)    this is value one  
(02)    and this is 2   
(03)    and this is number 3

Пока мой код:

$s="(01) this is value one (02) and this is 2 (03) and this is number 3" 
$pattern  = '(\(\d\d\))(.*)' 
$m = $s | select-string $pattern -AllMatches | % {$_.matches} | ForEach-Object { $_.Groups[1].Value }

Как выполнитьэто?

Ответы [ 4 ]

0 голосов
/ 05 декабря 2018

Поскольку вы ищете пары ключ-значение , имеет смысл собрать их в (упорядоченном n) хеш-таблице .

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

# Input string
$s = '(01) this is value one (02) and this is 2 (03) and this is number 3'

# Initialize the output hashtable
$ht = [ordered] @{}

# Split the input string and fill the hashtable.
$i = 0; 
$s -split '(\(\d+\)) ' -ne '' | ForEach-Object { 
  if (++$i % 2) { $key = $_ } else { $ht[$key] = $_ }
}

# Output the hashtable
$ht

Выше приведены значения:

Name                           Value
----                           -----
(01)                           this is value one 
(02)                           and this is 2 
(03)                           and this is number 3

Примечание: Если вы не хотите включать в ключ включающий (...) (name), используйте
-split '\((\d+)\) ' вместо -split '(\(\d+\)) '

В приведенном выше примере строка разбивается на элементы массива, в которых пары смежных элементов представляют пары ключ-значение.Затем вызов ForEach-Object добавляет эти пары ключ-значение в выходную хеш-таблицу, решая, является ли входной элемент ключом или значением на основе того, является ли индекс элемента нечетным или четным.


Что касается что вы пытались :

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

Вы получите желаемые совпадения, если вместо этого будете использовать следующее регулярное выражение:
'(\(\d+\)) ([^(]+)'

То есть после сопоставлениятакие индексы, как (01) соответствуют только до, но не включая последующие (, если таковые имеются.

В контексте упрощенной версии вашей исходной команды , которая выводит пары ключ-значение в виде массива пользовательских объектов ([pscustomobject] экземпляров):

$s = '(01) this is value one (02) and this is 2 (03) and this is number 3'
$pattern  = '(\(\d+\)) ([^(]+)'
$s | Select-String $pattern -AllMatches | ForEach-Object {
  $_.matches | Select-Object @{ n='Name';  e = { $_.Groups[1].Value } },
                             @{ n='Value'; e = { $_.Groups[2].Value } }
}

Приведенные выше выходы:

Name Value
---- -----
(01) this is value one 
(02) and this is 2 
(03) and this is number 3

Обратите внимание, однако, что вышеприведенный вывод массив из пользовательских объектов , каждый из которых представляет значение ключаpair, которая отличается от решения в верхнем разделе, который создает одну хеш-таблицу, содержащую все пары ключ-значение.

0 голосов
/ 04 декабря 2018

Взятие 4 пробелов после (xx) литерала

$s="(01) this is value one (02) and this is 2 (03) and this is number 3"
$s -replace " (?=\(\d\d\))","`n" -replace "(?<=\(\d\d\)) +","   "

Пример вывода:

(01)    this is value one
(02)    and this is 2
(03)    and this is number 3

В приведенном выше RegEx используются обходные пути нулевой длины

  • первый заменяет начальный пробел CR
  • , второй заменяет любое количество конечных пробелов против ровно 4.
0 голосов
/ 04 декабря 2018

вот альтернативный метод, который использует строковые методы вместо регулярных выражений.он также сохраняет выходные данные в упорядоченной хэш-таблице.[ordered] просто для удобства - я хотел, чтобы дисплей был в последовательности, чтобы я мог подтвердить, что вывод был таким, как ожидалось.

переписал фильтр "пустые элементы", чтобы использовать Where-Object вместо .Where(), поскольку OP используется в версии PoSh до версии v4.

# fake reading in a text file
#    in real life, use Get-Content
$InStuff = @'
(01) this is value one (02) and this is 2 (03) and this is number 3
(01) One Bravo (03) Three Bravo
(02) Two Charlie
(111) OneThrice Delta (666) Santa Delta
(01) One Echo (03) Three Echo (05) Five Echo
'@ -split [environment]::NewLine

$LookupTable = [ordered]@{}

foreach ($IS_Item in $InStuff)
    {
    # OP cannot use the ".Where()" array method - that was added in ps4
    #foreach ($Split_Item in $IS_Item.Split('(').Where({$_}))
    $Split_ISI = $IS_Item.Split('(') |
        # this gets rid of the empty items
        Where-Object {$_}

    foreach ($SI_Item in $Split_ISI)
        {
        $Key = $SI_Item.Split(')')[0].Trim()
        $Value = $SI_Item.Split(')')[1].Trim()
        # the leading comma forces the input to be an array
        $LookupTable[$Key] += ,$Value
        }
    }

$LookupTable | Out-Host

$LookupTable['01'][0] | Out-Host
$LookupTable['02'][1] | Out-Host

output ...

Name                           Value
----                           -----
01                             {this is value one, One Bravo, One Echo}
02                             {and this is 2, Two Charlie}
03                             {and this is number 3, Three Bravo, Three Echo}
111                            {OneThrice Delta}
666                            {Santa Delta}
05                             {Five Echo}


this is value one
Two Charlie

главная проблема здесь в том, что ключ поиска ДОЛЖЕН быть строкой, поэтому цифры для прямого поиска должны быть заключены в кавычки - '01'вместо 01.

0 голосов
/ 04 декабря 2018

Мне удалось добиться желаемого результата с помощью следующего:

PS H:\> $pattern = '(\(\d\d\))([^(]*)'
PS H:\> $results = $s | Select-String $pattern -AllMatches
PS H:\> $results.Matches.Value
(01) this is value one
(02) and this is 2
(03) and this is number 3

Редактировать: Доступ к группам совпадений:

PS H:\> $results.Matches.Captures.Groups[0].value
(01) this is value one
PS H:\> $results.Matches.Captures.Groups[1].value
(01)
PS H:\> $results.Matches.Captures.Groups[2].value
 this is value one
PS H:\> $results.Matches.Captures.Groups[3].value
(02) and this is 2
PS H:\> $results.Matches.Captures.Groups[4].value
(02)
PS H:\> $results.Matches.Captures.Groups[5].value
 and this is 2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...