Должен ли я использовать \d или [0-9] для сопоставления цифр в регулярном выражении Perl?

Прочитав несколько вопросов / ответов за последние несколько недель, я увидел использование \d в perl регулярные выражения прокомментированы как некорректные. Как и в более поздних версиях Perl \d это не то же самое, что [0-9], как \d будет представлять любой символ Unicode, который имеет атрибут цифры, и что [0-9] представляет символы "0", "1", "2",..., "9".

Я ценю это в некоторых контекстах [0-9] будет правильная вещь для использования, а в других \d будет. Мне было интересно, какие люди считают правильным использовать по умолчанию?

Лично я нахожу \d обозначения очень краткие и выразительные, тогда как в сравнении [0-9] несколько громоздко Но у меня мало опыта в написании многоязычного кода, точнее, кода для языков, которые не вписываются в диапазон символов ASCII и поэтому могут быть наивными.

я заметил

$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\\d' | wc -l
  298
$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\[0-9\]' | wc -l
  26

9 ответов

Решение

Для максимальной безопасности я бы предложил использовать [0-9] в любое время, когда вы специально не собираетесь совпадать со всеми цифрами, определенными юникодом.

Perldoc Perluniintro, Perl не поддерживает использование цифр, кроме [0-9] как числа, так что я бы определенно использовал [0-9] если оба условия верны:

  1. Вы хотите использовать результат как число (например, выполнять математические операции с ним или хранить его где-то, что принимает только правильные числа (например, столбец INT в базе данных)).

  2. Можно не цифрами [^0-9] будет присутствовать в данных таким образом, что регулярное выражение может соответствовать им. (Обратите внимание, что это всегда следует считать верным для ненадежного / враждебного ввода.)

Если какой-либо из них является ложным, то редко будет причина специально не использовать \d (и вы, вероятно, сможете сказать, когда это так), и если вы пытаетесь сопоставить все определяемые юникодом цифры, вы определенно захотите использовать \d,

Мне кажется очень опасным в использовании \dЭто плохое дизайнерское решение на языке, так как в большинстве случаев вы хотите [0-9], Хаффман-кодирование будет диктовать использование \d для чисел ASCII.

Большинство предыдущих постеров уже подчеркивали, почему вы должны использовать [0-9]Итак, позвольте мне дать вам немного больше данных:

  • Если я правильно читаю графики Юникода۷۰'это число (70 в знаке, не верьте мне на слово).

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

    $ perl -le '$one = chr 0xFF11; print "$one + 1 = ", $one+1;'
    1 + 1 = 1
    
  • Вот неполный список действительных чисел (которые могут отображаться или не отображаться в вашем браузере должным образом, в зависимости от используемых вами шрифтов), для каждого числа только первый из тех, которые интерпретируются как число при выполнении арифметики с Perl, как показано выше:

     ZERO:  0٠۰߀०০੦૦୦௦౦೦൦๐໐0
     ONE:   1١۱߁१১੧૧୧௧౧೧൧๑໑1
     TWO:   2٢۲߂२২੨૨୨௨౨೨൨๒໒2
     THREE: 3٣۳߃३৩੩૩୩௩౩೩൩๓໓3
     FOUR:  4٤۴߄४৪੪૪୪௪౪೪൪๔໔4
     FIVE:  5٥۵߅५৫੫૫୫௫౫೫൫๕໕5
     SIX:   6٦۶߆६৬੬૬୬௬౬೬൬๖໖6
     SEVEN: 7٧۷߇७৭੭૭୭௭౭೭൭๗໗7
     EIGHT: 8٨۸߈८৮੮૮୮௮౮೮൮๘໘8
     NINE:  9٩۹߉९৯੯૯୯௯౯೯൯๙໙9��
    

Вы все еще не убеждены?

Согласно Perlreref, "\d'с учетом локали и Unicode.

Однако, если используемый вами кодовый набор не является Unicode, вам не нужно беспокоиться о цифрах Unicode, и если используемый вами кодовый набор похож на Latin-1 (ISO 8859-1 или 8859-15), тогда знание локали также не повредит вам, потому что кодовый набор не содержит никаких других цифровых символов.

Таким образом, для многих людей большую часть времени вы можете использовать\dбез беспокойства. Однако, если данные Unicode являются частью вашей работы, вам нужно более тщательно продумать, что вам нужно.

Так же, как взломать сайт с орбиты, [0-9] это единственный способ быть уверенным. Да, это ужасно Да, выбор сделать \d быть ЮНИКОДОМ и знать язык был глупым. Но это наша кровать, и мы должны лежать в ней.

Что касается людей, которые склоняют головы в песке и говорят, что это не влияет на набор символов, который они используют сегодня, то, возможно, вы используете этот набор символов сегодня, но остальной мир использует UTF-8 сейчас, и вы будете используя это скоро также. Не забывайте кодировать, как парень, который поддерживает ваш код, - маньяк-убийца, который знает, где вы живете.

Да, а что касается использования модулей Perl \d против [0-9] Даже ядро ​​все еще имеет проблемы с Юникодом.

Если вы на самом деле имеете в виду любую цифру, но хотите иметь возможность вычислять результаты, вы можете использовать Text::Unidecode:

#!/usr/bin/perl

use strict;
use warnings;

use Text::Unidecode;

my $number = "\x{1811}\x{1812}\x{1813}\x{1814}\x{1815}";
print "$number is ", unidecode($number), "\n";

После еще одного тестирования это выглядит так: Text::Unidecode не обрабатывает все цифровые символы правильно. Я пишу модуль, который будет работать.

Я чувствую, что оба должны иметь свое место. Тем не менее, в 99,999% случаев (особенно в моем закрытом большом американском мире сотрудничества) они взаимозаменяемы. Я использую perl для манипулирования данными каждый день, и ни в одном из наборов данных, с которыми я имею дело, нет ли числа, которые не вписываются в [0-9], Тем не менее, я ценю, что есть важное различие между \d а также[0-9] и хорошо осознавать эту разницу. я использую \d потому что это кажется более лаконичным (как вы сказали) и никогда не будет "неправильным" в моем маленьком мире манипулирования данными.

Если вы подаете заявку \d в строку Unicode (например, в "\X{660}" =~ /\d/), он будет соответствовать цифре Unicode. Если вы подаете заявку \d в двоичную строку (например, UTF-8 эквивалент вышеупомянутого: "\xd9\xa0" =~ /\d/), он будет соответствовать только 10 цифрам ASCII. Perl 5.8 не создает строки Unicode по умолчанию (если только вы не спросите об этом, например, в "\X{...}" или же use utf8; так далее.).

Поэтому мой совет: обращайте внимание только на разницу между \d а также [0-9] если ваше приложение использует строки Unicode.

Основное возражение выше для использования\dкажется, это числовые цифры, отличные от ascii.

Этого можно избежать с помощью/aвариант. например:

      m/\d/a

Это ограничивает соответствие цифр только ASCII.

https://perldoc.perl.org/perlre#/a-(and-/aa):

Под /a \d всегда означает именно цифры от «0» до «9».

Если [0-9] чувствует себя неуклюжим, возможно, вы могли бы определить: $d=qr/[0-9]/; и использовать это вместо \d,

По мере того, как элементы управления форматом данных увеличиваются, потребность в специфичности шаблона уменьшается...

Например, если вы сопоставляете фрагмент данных, который был сгенерирован машиной, и всегда следует тем же правилам форматирования вывода, вам не нужно быть таким точным. Возьмите IPv4-адреса. если вы пытаетесь извлечь IP-адрес из строки конфигурации интерфейса маршрутизатора, все, что вам действительно нужно, это что-то вроде:

 'ip\haddress\h(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\D'

Если, с другой стороны, вы пытаетесь найти IP-адрес, встроенный где-то глубоко, скажем, в X-заголовок электронной почты, или если вы пытаетесь проверить IP-адрес, ну... это целая другая история!

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