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

Прочитав несколько вопросов / ответов за последние несколько недель, я увидел, что использование \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

Ответы [ 8 ]

54 голосов
/ 21 мая 2009

Мне кажется очень опасным использовать \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��
    

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

38 голосов
/ 21 мая 2009

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

Per perldoc perluniintro , Perl не поддерживает использование цифр, отличных от [0-9], в качестве чисел, поэтому я бы определенно использовал [0-9], если выполняются оба следующих условия:

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

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

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

8 голосов
/ 21 мая 2009

Согласно perlreref , '\d' учитывает локали и Unicode.

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

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

5 голосов
/ 21 мая 2009

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

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

О, а что касается модулей Perl, использующих \d против [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 не обрабатывает все цифровые символы правильно. Я пишу модуль , который будет работать.

3 голосов
/ 21 мая 2009

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

2 голосов
/ 21 мая 2009

Если вы примените \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.

1 голос
/ 21 мая 2009

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

0 голосов
/ 24 июня 2016

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

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

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

ЕСЛИ, с другой стороны, вы пытаетесь найти IP-адрес, встроенный где-то глубоко, например, в X-заголовок электронной почты, или если вы пытаетесь ВАЛИДИРОВАТЬ IP-адрес, ну ... это целое » другая история!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...