Должен ли я использовать \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-адрес, хорошо... это целое ' история истории!