Разница между \ A \ z и ^ $ в регулярных выражениях Ruby

196

В документации я читаю:

Используйте \ A и \ z, чтобы соответствовать началу и концу строки, ^ и $ соответствуют началу / концу строки.

Я собираюсь применить регулярное выражение, чтобы проверить имя пользователя (или адрес электронной почты тот же), представленный пользователем. Какое выражение мне следует использовать validates_format_ofв модели? Я не могу понять разницу: я всегда использовал ^ и $ ...

collimarco
источник

Ответы:

226

Если вы используете регулярное выражение для проверки, вы всегда хотите использовать \Aи \z. ^и $будет совпадать только до символа новой строки, что означает, что они могут использовать электронную почту, подобную ей, me@example.com\n<script>dangerous_stuff();</script>и при этом проверять ее, поскольку регулярное выражение видит только все до \n.

Я бы порекомендовал полностью удалить новые строки из имени пользователя или электронной почты заранее, так как для этого нет достаточных оснований. Тогда вы можете смело использовать ЛИБО \A \zили ^ $.

Люк
источник
13
@Ragmaanir прав, это должно быть с маленькой буквы \zвместо \Z!
Петр
11
+1 Спасибо! Хотя я бы не согласился с вашей рекомендацией: A) Не добавляйте ненужную работу / обработку, если есть подходящее универсальное средство, и B), особенно если это не позволяет вам лениться в различении между ними. Возможно, вы не всегда в состоянии манипулировать строками, только для Regex, так что оставьте правильный в памяти и почувствуйте разницу!
dooleyo
1
Я не понимал пример с опасными вещами, потому что в любом случае можно включить опасные вещи в строку, с новыми строками или без них, это будет эксплойт, который должен быть исправлен с помощью очистки и проверки html.
Джей Мотта
2
@JayrMotta демонстрирует то, что опасные вещи полностью обойдут всю проверку регулярных выражений . Таким образом, даже если вы проверяете наличие опасных элементов в своем регулярном выражении, оно обойдется, если $вместо этого вы будете проверять «конец строки» \z.
Доктор Блю,
178

По словам Кирки :

^ Соответствует началу строки.

$ Соответствует концу строки.

\A Соответствует началу строки.

\z Соответствует концу строки.

\Z Соответствует концу строки, если строка не заканчивается на a "\n", в этом случае она совпадает непосредственно перед "\n".

Итак, используйте \Aи строчные \z. Если вы используете \Zкого-то, может проникнуть в символ новой строки. Я думаю, это не опасно, но может испортить алгоритмы, которые предполагают, что в строке нет пробелов. В зависимости от вашего регулярного выражения и ограничений длины строки, кто-то может использовать невидимое имя только с символом новой строки.

Реализация JavaScript в Regex трактуется \Aкак литерал 'A'( ref ). Так что следи за собой и проверяй.

Ragmaanir
источник
16

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

мое
имя
является
Эндрю

Обратите внимание , что строка имеет много строк в нем - ^и $символы позволяют соответствовать начало и конец этих линий ( в основном лечащих на \nсимвол как разделитель) , а \Aи \Zпозволит вам соответствовать начало и конец всей строки.

Эндрю Хэйр
источник
1
Лучший ответ на мой взгляд. «В основном, трактовка символа \ n как разделителя» действительно помогла мне понять, спасибо.
Flyout91
11

Разница по примеру

  1. /^foo$/соответствует любому из следующего, /\Afoo\z/не соответствует:
whatever1
foo
whatever2
foo
whatever2
whatever1
foo
  1. /^foo$/и /\Afoo\z/все соответствуют следующему:
foo
Чун ян
источник