Должен ли я использовать \d или [0-9] для сопоставления цифр в регулярном выражении Perl?
Прочитав несколько вопросов/ответов за последние несколько недель, я видел использование \d
в регулярных выражениях perl, прокомментированных как некорректные. Как и в более поздних версиях perl \d
, это не то же самое, что [0-9]
, поскольку \d
будет представлять любой символ Юникода, который имеет атрибут digit, и что [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
Ответы
Ответ 1
Для максимальной безопасности я предлагаю использовать [0-9]
в любое время, когда вы специально не собираетесь сопоставлять все цифры, определенные в unicode.
Per perldoc perluniintro, Perl не поддерживает использование цифр, отличных от [0-9]
, как числа, поэтому я определенно использовал бы [0-9]
если верно следующее:
-
Вы хотите использовать результат как число (например, выполнять на нем математические операции или хранить его где-нибудь, только принимающий правильные номера (например, столбец INT в базе данных)).
-
Возможно, в данных будут присутствовать нецифровые символы [^0-9]
таким образом, чтобы регулярное выражение могло соответствовать им. (Обратите внимание, что это всегда следует считать истинным для недоверенного/враждебного ввода.)
Если любой из них является ложным, редко будет причина специально не использовать \d
(и вы, вероятно, сможете сказать, когда это так), и если вы пытаетесь сопоставить весь unicode -пределенные цифры, вы обязательно захотите использовать \d
.
Ответ 2
Мне кажется очень опасным использовать \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��
Вы все еще не уверены?
Ответ 3
В соответствии с perlreref, '\d
' - это знание локали и Unicode.
Однако, если используемый вами кодовый набор не является Unicode, вам не нужно беспокоиться о цифрах Unicode, и если код, который вы используете, похож на Latin-1 (ISO 8859-1 или 8859- 15), тогда осознание локали не повредит вам, потому что код не содержит никаких других цифровых символов.
Таким образом, для многих людей, большую часть времени, вы можете использовать "\d
" без забот. Однако, если данные Unicode являются частью вашей работы, вам необходимо более внимательно рассмотреть, что вы делаете.
Ответ 4
Так же, как nuking сайт с орбиты, [0-9]
- единственный способ убедиться. Да, это уродливо. Да, выбор сделать \d
должен быть UNICODE, и знание локали было глупо. Но это наша кровать, и мы должны лежать в ней.
Что касается людей, которые ныряют головами в песок, говоря, что это не влияет на набор символов, который они используют сегодня, хорошо, что вы можете использовать этот набор символов сегодня, но в остальном мире используется UTF-8 сейчас и вы также будете использовать его в ближайшее время. Помните, что код, подобный парню, который поддерживает ваш код, является убийственным маньяком, который знает, где вы живете.
О, а для модулей Perl, использующих \d
vs [0-9]
, даже ядро все еще проблемы UNICODE.
Если вы действительно имеете в виду любую цифру, но хотите иметь возможность делать математику с результатами, вы можете использовать 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 не обрабатывает все символы цифр правильно. Я пишу модуль, который будет работать.
Ответ 5
Я чувствую, что оба должны иметь свое место. Однако 99,999% времени (особенно в моем закрытом крупном мире американского сотрудничества) они взаимозаменяемы. Я использую perl для манипулирования данными каждый день, и ни в одном из наборов данных, с которыми я имею дело, есть номера, которые не помещаются в [0-9]
. Тем не менее, я понимаю, что существует важное различие между \d
и [0-9]
и его хорошим знанием об этой разнице. Я использую \d
, потому что он кажется более кратким (как вы сказали) и никогда не будет "неправильным" в моем маленьком мире манипуляции с данными.
Ответ 6
Если вы примените \d
к строке Unicode (например, в "\X{660}" =~ /\d/
), она будет соответствовать значению Unicode. Если вы примените \d
к двоичной строке (например, эквивалент UTF-8 выше: "\xd9\xa0" =~ /\d/
), она будет соответствовать только десятизначным цифрам ASCII. Perl 5.8 не создает строки Unicode по умолчанию (если вы специально не запрашиваете его, например, в "\X{...}"
или use utf8;
и т.д.).
Итак, мой совет: обратите внимание на разницу между \d
и [0-9]
, если ваше приложение использует строки Unicode.
Ответ 7
Если [0-9]
чувствует себя неуклюжим, возможно, вы можете определить: $d=qr/[0-9]/;
и использовать это вместо \d
.
Ответ 8
По мере того, как управление форматами данных возрастает, потребность в специфичности шаблона снижается...
Например, если вы соответствуете части данных, которые были сгенерированы машиной и всегда следует тем же правилам форматирования вывода, вам не нужно быть настолько точным.
Возьмите адреса IPv4. если вы пытаетесь извлечь IP-адрес из строки конфигурации интерфейса маршрутизатора, все, что вам действительно нужно, это что-то вроде:
'ip\haddress\h(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\D'
ЕСЛИ, с другой стороны, вы пытаетесь найти IP-адрес, встроенный глубоко где-то в, скажем, в адрес электронной почты X-Header, или если вы пытаетесь VALIDATE IP-адрес, хорошо... это целое ' история истории!