Как я могу избежать литеральной строки, которую я хочу интерполировать в регулярное выражение?

Есть ли встроенный способ избежать строки, которая будет использоваться в/в качестве регулярного выражения? Например.

www.abc.com

Сбежавшая версия будет:

www\.abc\.com

Я собирался использовать:

$string =~ s/[.*+?|()\[\]{}\\]/\\$&/g; # Escapes special regex chars

Но я просто хотел удостовериться, что нет более чистой встроенной операции, которую мне не хватает?

Ответы

Ответ 1

Используйте quotemeta или \Q...\E.

Рассмотрим следующую тестовую программу, которая соответствует $str as-is, с quotemeta и с \Q...\E:

#! /usr/bin/perl

use warnings;
use strict;

my $str = "www.abc.com";

my @test = (
  "www.abc.com",
  "www/abc!com",
);

sub ismatch($) { $_[0] ? "MATCH" : "NO MATCH" }

my @match = (
  [ as_is => sub { ismatch /$str/ } ],
  [ qmeta => sub { my $qm = quotemeta $str; ismatch /$qm/ } ],
  [ qe    => sub { ismatch /\Q$str\E/ } ],
);

for (@test) {
  print "\$_ = '$_':\n";

  foreach my $method (@match) {
    my($name,$match) = @$method;

    print "  - $name: ", $match->(), "\n";
  }
}

Обратите внимание на результат, что использование строки as-is может привести к ложным совпадениям:

$ ./try
$_ = 'www.abc.com':
  - as_is: MATCH
  - qmeta: MATCH
  - qe: MATCH
$_ = 'www/abc!com':
  - as_is: MATCH
  - qmeta: NO MATCH
  - qe: NO MATCH

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

Ответ 2

Лучший способ сделать это - использовать \Q, чтобы начать цитированную строку и \E, чтобы закончить ее.

my $foo = 'www.abc.com';
$bar =~ /blah\Q$foo\Eblah/;

Вы также можете использовать quotemeta для переменной. Например.

my $quoted_foo = quotemeta($foo);

Трюк \Q описан в perlre в разделе "Escape Sequences".