4

我需要创建正则表达式来验证用户是否输入:

  • 4 位数字
  • XXXXXX-YY这样的值,其中 X 是从 I 到 XXXIII 的罗马数字,YY 是两个拉丁字符 (AZ)
4

3 回答 3

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
于 2012-02-18T13:49:05.890 回答
2

那么匹配 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";
于 2012-02-18T12:27:25.647 回答
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 的最小数量的唯一模式(即,“那么你应该数到 33,不多也不少。三十三应该是你要数的数字,并且数数应为三十三。三十四不可数,三十二也不可数,除非你接着数到三十三。三十五就出来了。”)
  5. 意识到多达 39 个是单个模式(^(([X]{0,3}([I]([XV]?|[I]{0,2})?|([V][I]{0,3})?)))$为了更清晰,更改为捕获组)。
  6. 更改模式以允许最多二十九个。
  7. 添加另一个以允许三十到三十九。
  8. 构建整个模式并在 RegexBuddy(一个非常宝贵的工具)中针对数字 0 - 20,000 和罗马数字 1 - 150 以及后跟“-AA”进行测试。
  9. 这个模式奏效了,所以我把它贴了出来(然后又拿了一杯咖啡,并自我管理了一个“阿塔男孩”,以完成我认为是一个可爱的周六早上挑战)。

通过无关的括号,我假设您的意思是非捕获组(?: ... )。我经常使用这些来对事物进行分组(在这里分组是非常必要的)。我让它们不捕获,因为我不需要捕获子组,只捕获父组(在这个用例中,我认为它们也不需要实际捕获,但这样做并没有什么坏处)。通过使它们不被捕获,它们不会创建加速处理的反向引用(尽管对于单个输入,所获得的时间可以忽略不计)。

于 2012-02-18T12:30:56.920 回答