Многие движки регулярных выражений соответствуют .*
дважды в одной строке, например, при выполнении замены строки на основе регулярных выражений:
- 1-е совпадение - по определению- вся (однострочная) строка, как и ожидалось.
Во многих движках есть 2-е совпадение, а именно пустая строка ;то есть, хотя 1-е совпадение использовало всю входную строку, .*
снова сопоставляется снова , что затем соответствует пустой строке в конце входной строки.
- Примечание: Чтобы убедиться, что найдено только одно соответствие, используйте
^.*
Мои вопросы:
Есть ли веская причина для такого поведения?Как только входная строка будет использована полностью, я не ожидаю еще одной попытки найти совпадение.
Кроме проб и ошибок, вы можете почерпнуть из документации / regex dialect /поддерживаемые стандартом, какие двигатели демонстрируют такое поведение?
Обновление : полезный ответ Revo объясняет как изтекущее поведение;Что касается потенциала , почему , см. этот связанный вопрос .
Языки / платформы, которые ДЕЙСТВУЮТ поведение:
# .NET, via PowerShell (behavior also applies to the -replace operator)
PS> [regex]::Replace('a', '.*', '[$&]'
[a][] # !! Note the *2* matches, first the whole string, then the empty string
# Node.js
$ node -pe "'a'.replace(/.*/g, '[$&]')"
[a][]
# Ruby
$ ruby -e "puts 'a'.gsub(/.*/, '[\\0]')"
[a][]
# Python 3.7+ only
$ python -c "import re; print(re.sub('.*', '[\g<0>]', 'a'))"
[a][]
# Perl 5
$ echo a | perl -ple 's/.*/[$&]/g'
[a][]
# Perl 6
$ echo 'a' | perl6 -pe 's:g/.*/[$/]/'
[a][]
# Others?
Языки / платформы, на которых НЕ проявляется такое поведение:
# Python 2.x and Python 3.x <= 3.6
$ python -c "import re; print(re.sub('.*', '[\g<0>]', 'a'))"
[a] # !! Only 1 match found.
# Others?
bobble bubble поднимает несколько полезных вопросов:
Если вы сделаете этоленивый, как .*?
, вы можете получить 3 совпадений в некоторых и 2 совпадений в других .То же самое с .??
.Как только мы используем начальный якорь, я думал, что мы должны получить только одно совпадение, но интересно, что ^.*?
дает два совпадения в PCRE для a
, тогда как ^.*
должно привести к одному совпадениюповсюду.
Вот фрагмент PowerShell для тестирования поведения на разных языках с несколькими регулярными выражениями:
Примечание: Предполагаетсячто Python 3.x доступен как python3
, а Perl 6 - как perl6
.
Вы можете вставить весь фрагмент непосредственно в командную строку и вызвать его из истории для изменения входных данных.
& {
param($inputStr, $regexes)
# Define the commands as script blocks.
# IMPORTANT: Make sure that $inputStr and $regex are referenced *inside "..."*
# Always use "..." as the outer quoting, to work around PS quirks.
$cmds = { [regex]::Replace("$inputStr", "$regex", '[$&]') },
{ node -pe "'$inputStr'.replace(/$regex/g, '[$&]')" },
{ ruby -e "puts '$inputStr'.gsub(/$regex/, '[\\0]')" },
{ python -c "import re; print(re.sub('$regex', '[\g<0>]', '$inputStr'))" },
{ python3 -c "import re; print(re.sub('$regex', '[\g<0>]', '$inputStr'))" },
{ "$inputStr" | perl -ple "s/$regex/[$&]/g" },
{ "$inputStr" | perl6 -pe "s:g/$regex/[$/]/" }
$regexes | foreach {
$regex = $_
Write-Verbose -vb "----------- '$regex'"
$cmds | foreach {
$cmd = $_.ToString().Trim()
Write-Verbose -vb ('{0,-10}: {1}' -f (($cmd -split '\|')[-1].Trim() -split '[ :]')[0],
$cmd -replace '\$inputStr\b', $inputStr -replace '\$regex\b', $regex)
& $_ $regex
}
}
} -inputStr 'a' -regexes '.*', '^.*', '.*$', '^.*$', '.*?'
Пример вывода для регулярного выражения ^.*
, который подтверждает ожидание всплывающего пузырька, что при использовании начального якоря (^
) выдается только один совпадение на всех языках:
VERBOSE: ----------- '^.*'
VERBOSE: [regex] : [regex]::Replace("a", "^.*", '[$&]')
[a]
VERBOSE: node : node -pe "'a'.replace(/^.*/g, '[$&]')"
[a]
VERBOSE: ruby : ruby -e "puts 'a'.gsub(/^.*/, '[\\0]')"
[a]
VERBOSE: python : python -c "import re; print(re.sub('^.*', '[\g<0>]', 'a'))"
[a]
VERBOSE: python3 : python3 -c "import re; print(re.sub('^.*', '[\g<0>]', 'a'))"
[a]
VERBOSE: perl : "a" | perl -ple "s/^.*/[$&]/g"
[a]
VERBOSE: perl6 : "a" | perl6 -pe "s:g/^.*/[$/]/"
[a]