Обратная ссылка Powershell в пределах видимости - PullRequest
1 голос
/ 17 апреля 2020

Я собираюсь сопоставить строки, которые содержат определенную строку дважды.
Все содержимое показано ниже, я сохранил его в файле 1.txt.

    &nbsp;&nbsp;<b><font color="#5b4636">mit ~ und <u>Kegel</u></font></b> <span class="Icon">hum</span> <span class="Icon">fam</span> with the whole family;<br>
&nbsp;&nbsp;<b><font color="#5b4636">aus ~ern werden <u>Leute</u></font></b> <span class="Icon">prov</span> children grow up [all too] quickly;<br>
&nbsp;&nbsp;<b><font color="#5b4636">das ~ muss einen <u>Namen</u> haben</font></b> it must be called something;<br>
&nbsp;&nbsp;<b><font color="#5b4636">das ~ beim [rechten] <u>Namen</u> nennen</font></b> to call a spade a spade;<br>
&nbsp;&nbsp;<b><font color="#5b4636">~er und <u>Narren</u></font></b> [<i><font color="black">o</font></i> <b><font color="#5b4636"><u>Betrunkene</u></font></b>] <b><font color="#5b4636">sagen die Wahrheit</font></b> (<i><font color="black">sagen die Wahrheit</font></i>) children and fools speak the truth <span class="Icon">prov</span><br>
&nbsp;&nbsp;<b><font color="#5b4636">kleine ~er, kleine <u>Sorgen</u>, große ~er, große Sorgen</font></b> (<i><font color="black">große ~er, große Sorgen</font></i>) children when they are little make parents fools, when great, mad [<i><font color="black">or</font></i> they are great they make them mad] <span class="Icon">prov</span><br>
&nbsp;&nbsp;<b><font color="#5b4636">kein ~ von <u>Traurigkeit</u> sein</font></b> <span class="Icon">sein</span> to be sb who enjoys life;<br>
&nbsp;&nbsp;<b><font color="#5b4636">ich bin kein ~ von Traurigkeit</font></b> I [like [<i><font color="black">or</font></i> know how] to] enjoy life;<br>
&nbsp;&nbsp;<b><font color="#5b4636">ein ~ seiner <u>Zeit</u> sein</font></b> to be a child of one's time;<br>
&nbsp;&nbsp;<b><font color="#5b4636">[ein] <u>gebranntes</u> ~ scheut das Feuer</font></b> once bitten, twice shy <span class="Icon">prov</span><br>
&nbsp;&nbsp;<b><font color="#5b4636">was Glücksspiele angeht, bin ich ein gebranntes ~!</font></b> I've learned my lesson as far as games of chance are concerned;<br>
&nbsp;&nbsp;<b><font color="#5b4636">bei jdm <u>lieb</u> ~ sein</font></b> <span class="Icon">fam</span> to be sb's favourite [<i><font color="black">or</font></i> blue-eyed boy] [<i><font color="black">or</font></i> girl];<br>

Мой код для сопоставления строк: :

$content = Get-Content "D:\1.txt" -Encoding UTF8
foreach ($line in $content) { $line -match "(?<=$($Matches[1]).*)\(<i><font color=`"black`">([^<]*)</font></i>\)"}

False 
False 
False 
False 
False 
True  
False 
False 
False 
False 
False 
False

Возвращает истину только в строке6. Однако, если я сопоставлю его без части «lookbehind», она вернет true в обеих строках 5 и 6.

foreach ($line in $content) { $line -match "\(<i><font color=`"black`">([^<]*)</font></i>\)"}
False
False
False
False
True
True
False
False
False
False
False
False

Так что же не так с моим первым кодом регулярного выражения? Я использую Powershell 5.1.

1 Ответ

2 голосов
/ 17 апреля 2020

Из того, что я могу сказать, в то время как . NET regex engine - к которому PowerShell предоставляет доступ - позволяет использовать обратных ссылок (например, \1) в обходные утверждения в принципе, это не работает в вашем сценарии, который сводится к этому упрощенному примеру:

# !! Does NOT match, even though 'foo foo' -match '(?<=foo )(foo)' does
PS> 'foo foo' -match '(?<=\1 )(foo)'
False

Предположительно , обратная ссылка в шаблоне lookbehind соответствует до группы захвата и, следовательно, ничего не соответствует (обратная ссылка на группу захвата, которая (еще) не захватила что-либо, никогда не совпадает); Придуманный пример, где он работает (группа захвата на первом месте):
'foo foo' -match '(foo) .*(?<=\1)$'

Следовательно, ваша попытка (которая по ошибке использует $Matches[1] [ 1] вместо \1) не работает.

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

# Array of input lines.
$lines = @'
&nbsp;&nbsp;<b><font color="#5b4636">mit ~ und <u>Kegel</u></font></b> <span class="Icon">hum</span> <span class="Icon">fam</span> with the whole family;<br>
&nbsp;&nbsp;<b><font color="#5b4636">aus ~ern werden <u>Leute</u></font></b> <span class="Icon">prov</span> children grow up [all too] quickly;<br>
&nbsp;&nbsp;<b><font color="#5b4636">das ~ muss einen <u>Namen</u> haben</font></b> it must be called something;<br>
&nbsp;&nbsp;<b><font color="#5b4636">das ~ beim [rechten] <u>Namen</u> nennen</font></b> to call a spade a spade;<br>
&nbsp;&nbsp;<b><font color="#5b4636">~er und <u>Narren</u></font></b> [<i><font color="black">o</font></i> <b><font color="#5b4636"><u>Betrunkene</u></font></b>] <b><font color="#5b4636">sagen die Wahrheit</font></b> (<i><font color="black">sagen die Wahrheit</font></i>) children and fools speak the truth <span class="Icon">prov</span><br>
&nbsp;&nbsp;<b><font color="#5b4636">kleine ~er, kleine <u>Sorgen</u>, große ~er, große Sorgen</font></b> (<i><font color="black">große ~er, große Sorgen</font></i>) children when they are little make parents fools, when great, mad [<i><font color="black">or</font></i> they are great they make them mad] <span class="Icon">prov</span><br>
&nbsp;&nbsp;<b><font color="#5b4636">kein ~ von <u>Traurigkeit</u> sein</font></b> <span class="Icon">sein</span> to be sb who enjoys life;<br>
&nbsp;&nbsp;<b><font color="#5b4636">ich bin kein ~ von Traurigkeit</font></b> I [like [<i><font color="black">or</font></i> know how] to] enjoy life;<br>
&nbsp;&nbsp;<b><font color="#5b4636">ein ~ seiner <u>Zeit</u> sein</font></b> to be a child of one's time;<br>
&nbsp;&nbsp;<b><font color="#5b4636">[ein] <u>gebranntes</u> ~ scheut das Feuer</font></b> once bitten, twice shy <span class="Icon">prov</span><br>
&nbsp;&nbsp;<b><font color="#5b4636">was Glücksspiele angeht, bin ich ein gebranntes ~!</font></b> I've learned my lesson as far as games of chance are concerned;<br>
&nbsp;&nbsp;<b><font color="#5b4636">bei jdm <u>lieb</u> ~ sein</font></b> <span class="Icon">fam</span> to be sb's favourite [<i><font color="black">or</font></i> blue-eyed boy] [<i><font color="black">or</font></i> girl];<br>
'@ -split '\r?\n'                                                                            #'


foreach ($line in $lines) {
  # Note: To better illustrate the result, the doubled phrase
  #       rather than a Boolean is printed.
  if (
    $line -match '(?<before>.*)\(<i><font color="black">(?<phrase>[^<]+)</font></i>\)' 
      -and 
    $Matches.before -match [regex]::Escape($Matches.phrase)
  ) {
    $Matches[0]
  }
}   

Вышеуказанные значения (в строке 5 и 6 соответствуют удвоенным фразам):

sagen die Wahrheit
große ~er, große Sorgen

[1] automati c $Matches переменная в PowerShell заполняется после операции регулярного выражения, чтобы отразить то, что было захвачено, и заполняется, только если совпадение завершилось успешно . Это просто функция PowerShell, о которой движок. NET regex (который -match вызывает за кулисами) ничего не знает.

Встраивая $($Matches[1]) в расширяемую строку ( "..."), который служит в качестве регулярного выражения, поэтому вы (a) расширяете это значение (заменяя ссылку на переменную на ее значение) до механизм регулярных выражений видит строку, и (b) ссылаются на то, что самая последняя предыдущая операция успешного сопоставления была захвачена в ее первой группе захвата.

Вкратце: единственный способ использовать обратные ссылки в PowerShell - это использовать синтаксис движка. NET regex; например, \1 для обозначения первой группы захвата.

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