Perl регулярное выражение становится жадным при использовании (.*?) С якорями

У меня есть Perl регулярное выражение, чтобы добавить ссылку на видео YouTube в тег видео. Ссылка на видео YouTube может быть иногда внутри якорей, а иногда и без якорей. Я проверил привязку с любым значением, используя (.*?), Но он вел себя как жадный. ниже приведено регулярное выражение, которое я использую.

$text =~ s#(^|\s|\>)(?:<a(.*?)\>)?((http|https)://(?:www.)?(?:youtu.be/|youtube.com(?:/embed/|/v/|/watch\?v=|/watch\?[a-z_=]+&(amp;)?v=))([\w-]{11}))[\?&\w;\=\+\-\.]*(\<\/a\>)?#$1\[video\]$3\[\/video\]#isg;

Пожалуйста, помогите сделать его не жадным.

Образец входных данных:

<a rel="nofollow" href="https://www.facebook.com/photo.php?v=639296402756602" target="_blank">https://www.facebook.com/photo.php?v=639296402756602</a>

<a rel="nofollow" href="https://www.youtube.com/watch?v=9gTw2EDkaDQ" target="_blank">https://www.youtube.com/watch?v=9gTw2EDkaDQ</a>

Я ожидаю ниже выхода:

<a rel="nofollow" href="https://www.facebook.com/photo.php?v=639296402756602" target="_blank">https://www.facebook.com/photo.php?v=639296402756602</a>

[video]https://www.youtube.com/watch?v=9gTw2EDkaDQ[/video]

но он возвращает только ссылку на YouTube. он игнорирует ссылку на видео в Facebook.

[video]https://www.youtube.com/watch?v=9gTw2EDkaDQ[/video]

2 ответа

Вы действительно хотите соответствовать > персонажи? Бьюсь об заклад, вы не... Так что не используйте.* и это решит вашу проблему жадности. использование [^>]* вместо. Он гарантированно остановится, как только он достигнет первого > (даже без привязки к ?) так как > не совпадает

$text =~ s#(^|\s|\>)(?:<a(.*?)\>)?((http|https)://(?:www.)?(?:youtu.be/|youtube.com(?:/embed/|/v/|/watch\?v=|/watch\?[a-z_=]+&(amp;)?v=))([\w-]{11}))[\?&\w;\=\+\-\.]*(\<\/a\>)?#$1\[video\]$3\[\/video\]#isg;

Это регулярное выражение не читается, и никто не захочет его читать. Помните, что регулярные выражения тоже являются программами, и им тоже нужно форматировать код.

Всегда используйте модификаторы `smx` со всеми регулярными выражениями, это очень хорошая практика, например,` всегда использовать строгие и предупреждения`.

m - рассматривать строку как несколько строк. Таким образом, измените "^" и "$", сопоставляя начало или конец строки только в левом и правом концах строки, чтобы сопоставлять их в любом месте строки.

s - рассматривать строку как одну строку. То есть изменить "." соответствовать любому символу, даже символу новой строки, который обычно не соответствует. Используются вместе, как / мс, они позволяют "." соответствует любому символу, в то же время позволяя сопоставлять "^" и "$", соответственно, сразу после и непосредственно перед символами новой строки в строке.

x - Увеличьте разборчивость вашего шаблона, разрешая пробелы и комментарии.

Тогда ваш код будет выглядеть намного более читабельным, и вы увидите, что он содержит много неиспользуемых групп захвата, а также мертвый код и небольшие ошибки, например, использование unescaped `.` в группе захвата URL.

После всех модификаций и, как говорит Дейв Шерохман, использование `[^>]*` вместо `.*?` Ваш код будет выглядеть намного лучше, не так ли?. Проверь это:

$text =~ s{
                (?:<a[^>]*>)?
                (
                    http[s]?://
                    (?:www[.])?
                    youtu[.]?be(?:[.]com)?
                    (?:/embed/|/v/|/watch\?v=|/watch\?[a-z_=]+&(?:amp;)?v=)
                )
                ([\w-]{11})
                [^<]*
                (?:</a>)?
            }
            {
                \[video\]$1$2\[/video\]
            }smxgi;

И это работает отлично!

Другие вопросы по тегам