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


196

У документації я прочитав:

Використовуйте \ A і \ z, щоб співставити початок і кінець рядка, ^ і $ відповідно до початку / кінця рядка.

Я буду застосовувати регулярний вираз, щоб перевірити ім'я користувача (або електронна пошта - те саме), подане користувачем. Який вираз я повинен використовувати validates_format_ofв моделі? Я не можу зрозуміти різницю: я завжди використовував ^ і $ ...


Відповіді:


226

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

Моя рекомендація буде заздалегідь повністю позбавити нові рядки з імені користувача чи електронної пошти, оскільки для цього майже немає законних причин. Тоді ви можете сміливо використовувати EITHER \A \zабо ^ $.


13
@Ragmaanir має рацію, \zзамість цього має бути маленька літера \Z!
Петро

11
+1 Дякую! Хоча я повинен був би не погодитися з вашою рекомендацією: А) Не додайте зайвих робіт / обробку, якщо є відповідний вилов, і В) особливо не, якщо це дозволяє лінуватися про розмежування обох. Вам не завжди вдається скласти маніпуляції з рядками, тільки Regex, тому зафіксуйте потрібну пам'ять і знайте різницю!
dooleyo

1
Я не зрозумів приклад з небезпечними матеріалами, тому що в будь-якому випадку можна включити небезпечні речі в рядок, з новими рядками або без них, це буде експлуатуванням, який слід виправити за допомогою html санітарії та перевірки.
Jayr Motta

2
@JayrMotta, що показує демонстрація, це те, що небезпечний матеріал повністю обійшов би всю вашу перевірку регулярного вибору . Тож навіть якщо ви перевіряли небезпечні речі у своєму регулярному виразі, він би обійшов його, якщо ви $замість цього перевіряли "кінець рядка" \z.
Doctor Blue

178

За даними Pickaxe :

^ Відповідає початку рядка.

$ Збіг в кінці рядка.

\A Відповідає початку рядка.

\z Відповідає кінці рядка.

\Z Відповідає кінці рядка, якщо рядок не закінчується символом a "\n", у цьому випадку він відповідає безпосередньо перед "\n".

Отже, використовуйте \Aі малі літери \z. Якщо ви користуєтесь, \Zхтось може прокрастися в символі нового рядка. Думаю, це не є небезпечним, але може накрутити алгоритми, які припускають, що в рядку немає пробілів. Залежно від ваших регулярних виразів та обмежень довжини рядка, хтось може використовувати невидиме ім’я лише з символом нової лінії.

Реалізація Regex JavaScript розглядає \Aяк буквальне 'A'( посилання ). Тому дивіться себе там і випробовуйте.


16

Початок і кінець рядка не обов'язково можуть бути однаковими як початок і кінець рядка. Уявіть, якби ви використовували таке тестове рядок:

моє
ім'я
є
Ендрю

Зауважте, що в рядку є багато рядків - символи ^та $символи дозволяють вам співставляти початок і кінець цих рядків (в основному трактуючи \nсимвол як деліметр) \Aі \Zдозволяючи вам співставляти початок і кінець всього рядка.


1
Найкраща відповідь на мій погляд. "в основному трактування \ n символу як деліметру" дійсно допомогло мені зрозуміти, дякую.
Flyout91

11

Різниця за прикладом

  1. /^foo$/відповідає будь-якому з наведеного нижче, /\Afoo\z/не відповідає:
whatever1
foo
whatever2
foo
whatever2
whatever1
foo
  1. /^foo$/і /\Afoo\z/всі відповідають наступному:
foo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.