Как мне написать регулярное выражение, которое выполняет несколько подстановок в каждой строке, за исключением случаев, когда строка начинается с определенной строки? - PullRequest
3 голосов
/ 09 февраля 2009

Я пытаюсь написать регулярное выражение, которое окружает URL-адреса «http» угловыми скобками, за исключением строк, начинающихся с двух косых черт. Лучшее, что я придумал, это:

s#^(?!//)(.*?)(<a href="http://[" rel="nofollow noreferrer">http://[</a>^\s]+)#$1<$2>#gm;

Это прекрасно работает для этих двух:


Ввод: <a href="http://a.com">http://a.com</a>

Выход: <<a href="http://a.com">http://a.com</a>>


Ввод: //<a href="http://a.com">http://a.com</a>

Выход: //<a href="http://a.com">http://a.com</a>


Однако здесь это не получается:


Ввод: <a href="http://a.com">http://a.com</a> <a href="http://b.com" rel="nofollow noreferrer">http://b.com</a>

Фактический результат: <<a href="http://a.com">http://a.com</a>> <a href="http://b.com" rel="nofollow noreferrer">http://b.com</a>

Желаемый вывод: <<a href="http://a.com">http://a.com</a>> <<a href="http://b.com" rel="nofollow noreferrer">http://b.com</a>>


Почему мое регулярное выражение не совпадает? Я неправильно использую / g?

Ответы [ 3 ]

4 голосов
/ 09 февраля 2009

Вы действительно должны использовать два регулярных выражения; одна для идентификации «закомментированных» строк и одна для изменения http в обычных строках.

Может быть нестандартный способ объединить два регулярных выражения или заменить все ваши множественные (http ...) + совпадения, но я бы не стал их использовать.

3 голосов
/ 09 февраля 2009

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

s{
    (?:^|\G)     # start of the last match, so you never backtrack and don't capture.
    (?!//)       # a section without //
    (.*?)        # followed by anything
    (
        http://  # with http://
        [^\s]+   # and non-spaces - you could also use \S
    )
 }
 {$1<$2>}xmg;

Пробуя это в Perl, мы получаем:

sub test {
    my ($str, $expect) = @_;
    my $mod = $str;
    $mod =~ s{
            (?:^|\G)       # start of the last match, so you never backtrack.
            (?!//)       # a section without //
            (.*?)        # followed by anything
            (
                http://  # with http://
                [^\s]+   # and non-spaces - you could also use \S
            )
          }
          {$1<$2>}xmg;
    print "Expecting '$expect' got '$mod' - ";
    print $mod eq $expect ? "passed\n" : "failed\n";
}

test("http://foo.com",    "<http://foo.com>");
test("// http://foo.com", "// http://foo.com");
test("foo\nhttp://a.com","foo\n<http://a.com>");

# output is 
# Expecting '<http://foo.com>' got '<http://foo.com>' - passed
# Expecting '// http://foo.com' got '// http://foo.com' - passed
# Expecting 'foo
# <http://a.com>' got 'foo
# <http://a.com>' - passed

Редактировать: Пара изменений: добавлен модификатор 'm', чтобы убедиться, что он совпадает с начала строки, и измените \ G на (^ | \ G), чтобы убедиться, что он начинает смотреть в начале линия тоже.

3 голосов
/ 09 февраля 2009

Вы не можете сделать это для неограниченного числа выражений. Попробуйте это:

s#(http://[^\s]+)#<$1>#g unless m#^//#;

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

РЕДАКТИРОВАТЬ: мой ответ совпадает с ответом aib, но у меня есть код.

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