Regex Question: Сопоставление этого шаблона с жесткими или мягкими кавычками - PullRequest
0 голосов
/ 23 мая 2009

У меня есть это регулярное выражение для работы с якорем:

$p = '%<a.*\s+name="(.*)"\s*>(?:.*)</a>%im';

Это соответствует <a, за которым следует ноль или более, за которым следует пробел и name="

Он захватывает имена, даже если класс или идентификатор предшествуют имени в привязке.

Что я хотел бы добавить, так это возможность сопоставлять name=' с одинарной кавычкой ('), так как рано или поздно кто-то сделает это.

Очевидно, я мог бы просто добавить второе регулярное выражение, написанное для этого, но это выглядит не элегантно.

Кто-нибудь знает, как добавить одинарную кавычку и просто использовать одно регулярное выражение? Любые другие улучшения или рекомендации будут очень приветствоваться. Я могу использовать всю помощь по регулярным выражениям, которую я могу получить!

Большое спасибо за чтение,

function findAnchors($html) {
    $names = array();
    $p = '%<a.*\s+name="(.*)"\s*>(?:.*)</a>%im';
    $t = preg_match_all($p, $html, $matches, PREG_SET_ORDER);
    if ($matches) {
        foreach ($matches as $m) {
            $names[] = $m[1];
        }
        return $names;
    }
}

Ответы [ 5 ]

2 голосов
/ 23 мая 2009

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

$regex = '([\'"])(.*?)(.{0,2})(?<![^\\\]\\\)(\1)';

\ 1 - начальный разделитель, \ 2 - содержимое (минус 2 символа), \ 3 - последние 2 символа и конечный разделитель. Это регулярное выражение позволяет экранировать разделители, если экранирующий символ равен \, а экранирующий символ не экранирован. IE.

'Valid'
'Valid \' String'
'Invalid ' String'
'Invalid \\' String'
1 голос
/ 27 сентября 2011

Вот еще один подход:

$rgx='~<a(?:\s+(?>name()|\w+)=(?|"([^"]*)"|\'([^\']*)\'))+?\1~i';

Я знаю, что этот вопрос старый, но когда он всплыл, я только что придумал другое использование слова "пустые группы захвата как флажки" из Кулинарной книги . Первая группа без захвата обрабатывает сопоставление всех пар «имя = значение» под управлением неохотного плюса (+?). Если имя атрибута буквально name, пустая группа (()) ничего не соответствует, тогда обратная ссылка (\1) снова ничего не соответствует, выходя из цикла. (Обратная ссылка успешна, потому что группа участвовала в матче , хотя она не потребляла никаких символов.)

Значение атрибута фиксируется каждый раз в группе № 2, перезаписывая все, что было записано на предыдущей итерации. (Конструкция сброса ветви ((?|(...)|(...)) позволяет нам «повторно использовать» группу № 2 для захвата значения внутри кавычек, какими бы они ни были.) Поскольку цикл завершается после появления имени name, последнее захваченное значение соответствует этому атрибуту.

См. Демонстрацию по Ideone

1 голос
/ 24 мая 2009

Ваше текущее решение не будет сопоставлять якоря с другими атрибутами после имени (например, <a name="foo" id="foo">).

Попробуйте:

$regex = '%<a\s+\S*\s*name=["']([^"']+)["']%i'; 

Это извлечет содержимое атрибута name в обратную ссылку $1.
\s* также допускает разрывы строк между атрибутами.
Вам не нужно заканчивать с остальной частью тега 'a', поскольку класс отрицанных символов [^"']+ будет ленивым.

1 голос
/ 23 мая 2009

Попробуйте это:

/<a(?:\s+(?!name)[^"'>]+(?:"[^"]*"|'[^']*')?)*\s+name=("[^"]*"|'[^']*')\s*>/im

Здесь вам просто нужно удалить окружающие цитаты:

substr($match[1], 1, -1)

Но использование реального синтаксического анализатора, такого как DOMDocument , безусловно, было бы лучше, чем использование этого регулярного выражения.

1 голос
/ 23 мая 2009

Используйте [] для сопоставления наборов символов:

$p = "%<a.*\s+name=['\"](.*)['\"]\s*>(?:.*)</a>%im";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...