Perl угловые скобки в регулярных выражениях - PullRequest
1 голос
/ 14 февраля 2020

Я обнаружил следующий код:

my $string = "fo2345obar";
$string =~ s<(\d+)><$1\.>g;

Я не могу понять, что означают угловые скобки в этом контексте; все замены, которые я видел ранее, имели форму:

$string =~ s/(\d+)/$1\./g;

Что означают угловые скобки?

Ответы [ 4 ]

4 голосов
/ 14 февраля 2020

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

s/PATTERN/REPLACEMENT/
s=PATTERN=REPLACEMENT=
s,PATTERN,REPLACEMENT,

Это возможно и в sed.

Но, в Perl некоторые разделители являются особыми, потому что они входят в пары, например

s{PATTERN}{REPLACEMENT}
s<PATTERN><REPLACEMENT>
s(PATTERN)[REPLACEMENT]

et c.

3 голосов
/ 15 февраля 2020

Я хотел бы добавить (к многочисленным ответам), что в операторе s/// могут быть две разные пары разделителей.

@ choroba в своем ответе имел пример s()[], но не обращал на это особого внимания, поэтому я хочу добавить это для акцента.


Рассмотрим выражение замены регулярного выражения в форме s{aaa}{bbb}.

Это только если Первый разделитель непарный, что он будет диктовать разделитель для всего выражения. Затем разделители конца совпадения и начала замены в середине сочетаются (это один и тот же символ), и вместо s#aaa##bbb# вы получаете

s#aaa#bbb#

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

# not only
s{aaa}{bbb}

# but also
s{aaa}[bbb]

# and even
s{aaa}#bbb#
s{aaa}/bbb/

Это в основном полезно для таких вещей, как:

s{aaa}'$literalstring'

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


Хотя это обычно затрудняет восприятие кода (и, следовательно, не рекомендуется), я делаю обратите внимание на это здесь для полноты картины - вы можете встретить это в коде.

2 голосов
/ 14 февраля 2020

Традиционный способ изменить foo на bar в строке - это сделать:

$string =~ s/foo/bar/;

Это все хорошо, но что если foo и bar содержат много символов /? Например, что если вы хотите изменить все экземпляры http:// на https://? Вам нужно будет убрать символы / с помощью \, и вы увидите что-то вроде этого:

$string =~ s/http:\/\//https:\/\//;

Вы должны признать, что приведенная выше замена не так проста для глаз , Не так просто определить, какие / принадлежат s///, а какие http://. А символы \, используемые для экранирования символов /, только затрудняют понимание всей строки.

Некоторые люди называют это «синдромом склонности зубочистки», потому что все / и \ персонажи выглядят как зубочистки.

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

 $string =~ s#http://#https://#;
 $string =~ s@http://@https://@;
 $string =~ s!http://!https://!;
 $string =~ s|http://|https://|;

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

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

Есть много символов, которые вы можете использовать в качестве разделителей; Я не буду перечислять их здесь. Однако есть четыре специальных ограничителя скобка , которые входят в пары и окружают ваши выражения, как в скобках. Это: ( и ), [ и ], { и } и, наконец, < и >. Вы используете их так:

$string =~ s(http://)(https://);
$string =~ s<foo><bar>g;

Немного легче читать без всех этих зубочисток, не так ли?

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

Что немного странно в приведенном вами примере:

$string =~ s<(\d+)><$1\.>g;

Не существует ли символов / где-нибудь в выражении, так что, предположительно, это не более понятно, чем:

$string =~ s/(\d+)/$1\./g;

Однако, возможно, оригинальный кодер думал, что два символа \ будут контрастировать с символами /, и поэтому хотел избежать / разделители в целом.

Примечание: Вы не спрашивали об этом, но часть замены $1\. без необходимости экранирует символ .. Вам не нужен \ там, потому что вторая часть подстановки s/// не является регулярным выражением - это только замена, и . никогда не используется там, чтобы соответствовать символу. Так что нет смысла избегать его в вашем случае, так как . всегда означает литерал . там.

Так что вышеприведенная строка будет лучше записана как:

$string =~ s/(\d+)/$1./g;

I надеюсь, это поможет!

2 голосов
/ 14 февраля 2020

Perl документация для регулярное выражение определяет символы-разделители. В нескольких возможных случаях использования различных разделителей

$string =~ s/pattern/replacement/g;
$string =~ s{pattern}{replacement}g;
$string =~ s!pattern!replacement!g;
$string =~ s|pattern|replacement|g;
$string =~ s<pattern><replacement>g;
$string =~ s#pattern#replacement#g;
$string =~ s'pattern'replacement'g;
$string =~ s,pattern,replacement,g;

Наиболее распространенный используемый разделитель - /, но в некоторых ситуациях его использование делает шаблон менее читабельным

$path = '/home/user1/dir1/dir2';

Сравните эти три

$path =~ s/user1\/dir1\/dir2/user2\/dir3\/dir4/;
$path =~ s!user/dir1/dir2!user2/dir3/dir4!;
$path =~ s#user/dir1/dir2#user2/dir3/dir4#;

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

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

Учебное пособие perl регулярные выражения

Stackoverflow вопрос 21335765

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