2012-02-18 5 views
4

мне нужно создать регулярное выражение, которое проверяет, если пользователь вводит:Как создать регулярное выражение, проверяющее римские цифры?

  • 4 цифры ИЛИ
  • значение как XXXXXX-YY, где Х представляет собой римские цифры от I до XXXIII и YY это две латинские символы (AZ)
+2

Смотрите этот другой вопрос: http://stackoverflow.com/questions/267399/how -do-you-match-only-valid-roman-numbers-with-a-regular-expression – satoshi

+0

@RobW, это может быть от 1 до 6 символов, поскольку ожидаемое значение равно от I до XXXIII (т.е. от 1 до 33). –

ответ

3

В соответствии с требованиями, это возможные римские числовые форматы. Для удобства чтения отображается только максимальное количество X.

XXX III  (or: <empty>, I or II instead of III) 
XX V  (or: IV, IX and X instead of IV) 

Я предлагаю этот компактный шаблон:

/^(\d{4}|(?=[IVX])(X{0,3}I{0,3}|X{0,2}VI{0,3}|X{0,2}I?[VX])-[A-Z]{2})$/i 

Объяснение:

^    Begin of string 
(    Begin of group 1. 
    \d{4}    4 digits 

|     OR 

    (?=[IVX])   Look-ahead: Must be followed by a I, V or X 
    (     Begin of group 2. 
    X{0,3}I{0,3}  = 0 1 2 3 + { 0 ; 10 ; 20 ; 30} (roman) 
    |     OR 
    X{0,2}VI{0,3}  = 5 6 7 8 + { 0 ; 10 ; 20 }  (roman) 
    |     OR 
    X{0,2}I?[VX]  = 4 9  + { 0 ; 10 ; 20 }  (roman) 
)     End of group 2 
    -[A-Z]{2}   Postfixed by a hyphen and two letters 
)     End of group 1. 
$    End of string 
+0

Вау, это очень впечатляет! Требуется гораздо больше мышления, чем метод [Regexp :: Assemble] (http://search.cpan.org/perldoc?Regexp::Assemble). – tchrist

3

Ну та часть, которая соответствует римской цифрой между I и XXXIII является:

(?:X(?:X(?:V(?:I(?:I?I)?)?|X(?:I(?:I?I)?)?|I(?:[VX]|I?I)?)?|V(?:I(?:I?I)?)?|I(?:[VX]|I?I)?)?|V(?:I(?:I?I)?)?|I(?:[VX]|I?I)?) 

Как показали следующее:

#!/usr/bin/env perl 
use Regexp::Assemble; 
use Roman; 

my $ra = new Regexp::Assemble; 

for my $num (1..33) { 
    $ra->add(Roman($num)); 
} 

print $ra->re, "\n"; 
1
function inputIsValid(value) { 
    var r = /(^[0-9]{4}$)|(^(?:(?:[X]{0,2}(?:[I](?:[XV]?|[I]{0,2})?|(?:[V][I]{0,3})?))|(?:[X]{3}[I]{0,3}))\-[A-Z]{2}$)/ig; 
    return value.match(r); 
} 

Это будет соответствовать либо 4-значный вход, или римские цифры (в диапазоне 1 - 33), а затем тире и двух букв.

Чтобы объяснить регулярное выражение, ниже расширенный источник с комментариями:

// Test for a 4-digit number 
(          // Start required capturing group 
    ^         // Start of string 
    [0-9]{4}       // Test for 0-9, exactly 4 times 
    $         // End of string 
)          // End required capturing group 
|          // OR 
// Test for Roman Numerals, 1 - 33, followed by a dash and two letters 
(          // Start required capturing group 
    ^         // Start of string 
    (?:         // Start required non-capturing group 
     // Test for 1 - 29 
     (?:        // Start required non-capturing group 
      // Test for 10, 20, (and implied 0, although the Romans did not have a digit, or mathematical concept, for 0) 
      [X]{0,2}     // X, optionally up to 2 times 
      (?:       // Start required non-capturing group 
       // Test for 1 - 4, and 9 
       [I]      // I, exactly once (I = 1) 
       (?:      // Start optional non-capturing group 
        // IV = 4, IX = 9 
        [XV]?    // Optional X or V, exactly once 
        |     // OR 
        // II = 2, III = 3 
        [I]{0,2}   // Optional I, up to 2 times 
       )?      // End optional non-capturing group 
       |      // OR 
       // Test for 5 - 8 
       (?:      // Start optional non-capturing group 
        [V][I]{0,3}   // Required V, followed by optional I, up to 3 times 
       )?      // End optional non-capturing group 
      )       // End required non-capturing group 
     )        // End required non-capturing group 
     |        // OR 
     // Test for 30 - 33 
     (?:        // Start required non-capturing group 
      // Test for 30 
      [X]{3}      // X exactly 3 times 
      // Test for 1 - 3 
      [I]{0,3}     // Optional I, up to 3 times 
     )        // End required non-capturing group 
    )         // End required non-capturing group 
    // Test for dash and two letters 
    \-         // Literal -, exactly 1 time 
    [A-Z]{2}       // Alphabetic character, exactly 2 times 
    $         // End of string 
)          // End required capturing group 

4-значный номер и замыкающие \-[A-Z]{2} были (мне) самоочевидны. Мой метод для римских цифр состоял в том, чтобы:

  1. Открыть Excel Заполнить столбец 1-33.
  2. Преобразуйте эту колонку в римские цифры (всего 7 разных сортов).
  3. Проверьте, не отличались ли какие-либо разновидности от 1-33 (их не было).
  4. Свернутый с перемещением римских цифр в минимальное количество уникальных узоров, которые ограничивали их до 33 (т. Е. «Тогда вы будете считать до тридцати трех, не более, не менее». Тридцать три будут числом, которое вы должны подсчитать , а число подсчетов будет тридцать три. Тридцать четыре не засчитайте, и не посчитайте тридцать два, за исключением того, что тогда вы переходите к тридцати трем. Тридцать пять прямо. »)
  5. Понял, что до тридцати девяти - это один шаблон (^(([X]{0,3}([I]([XV]?|[I]{0,2})?|([V][I]{0,3})?)))$, который был изменен на группы захвата для большей ясности).
  6. Изменен шаблон, позволяющий до двадцати девяти.
  7. Добавлен еще один, чтобы разрешить тридцать-тридцать девять.
  8. Постройте весь шаблон и тест в RegexBuddy (бесценный инструмент для этого материала) против цифр 0 - 20 000 и римских цифр 1 - 150, а затем «-AA».
  9. Образец работал, поэтому я разместил его (затем схватил еще одну чашку кофе и самоуправлял «атта-мальчика» для завершения того, что, как я думал, было чудесным утром в субботу).

Посторонние скобки, я полагаю, вы имеете в виду группы, не захватывающие захват (?: ...). Я много использую для группировки вещей (и здесь очень нужна группировка). Я сделал их не захватывающими, потому что мне не нужно захватывать подгруппы, а только родительские группы (и в этом случае я не думаю, что они действительно должны быть захвачены, но это не мешает сделать это). Делая их не захватывая, они не будут создавать обратные ссылки, которые ускоряют обработку (хотя для одного входа время, полученное, незначительно).

+0

Как вы построили эти шаблоны и что со всеми посторонними скобками? – tchrist

+0

Нет, на самом деле, я имел в виду, почему вы написали '[V] [I] {0,3}' вместо 'VI {0,3}'. Кроме того, вы использовали неправильный символ комментария: regexes требуют '#'. О, подождите, это Javascript, где вам запрещено использовать режим '/ x' или' (? X) '. Javascript имеет худшие регулярные выражения любого языка. Просто ужасно. Однако плагин XRegExp помогает немного. – tchrist

+0

Я построил этот рисунок вручную. Точный метод теперь находится в сообщении. – pete