【问题标题】:Regex to match numbers written as words, digits or roman numerals正则表达式匹配写成单词、数字或罗马数字的数字
【发布时间】:2014-09-19 21:51:22
【问题描述】:

我正在尝试匹配以单词、数字或罗马数字形式编写的数字。这是一堆样本

CHAPTER 1
CHAPTER 2
CHAPTER THREE
CHAPTER IV
CHAPTER TWENTY TWO

我不擅长正则表达式,这就是我目前所掌握的。

(CHAPTER (([0-9]+)|(/* words - see below */)|( /* roman - see below */)))

// words
(TWENTY|THIRTY|etc)?( |-)?(ONE|TWO|THREE|FOUR|FIVE|etc)?

// roman
(I|II|III|IV|V|etc)+

该语句捕获第 1 章、第 2 章和第 3 章,但尝试将 IV 匹配为一个单词(我猜它与 FIVE 匹配?)。二十二 根本不匹配。

有人可以帮忙吗?这是完整的正则表达式

(CHAPTER (
([0-9]+)|
((TWENTY|THIRTY)?( |-)?(ONE|TWO|THREE|FOUR|FIVE)?)|
((I|II|III|IV|V)+)
))

注意:

这样做的目的是将这些文本表示形式转换为实际的整数。在每种情况下我都有方法可以做到这一点,所以我确实需要区分各种情况

【问题讨论】:

  • 您的CHAPTER IV 在这里写为CHAPTER !V,感叹号与I。如果这是您文件中的内容,则不会匹配。
  • 除非需要明确写出这些,否则CHAPTER (\w+(?: \w+)?)会更容易
  • @BobKaufman 在这种情况下这是一个错字。原文是对的
  • @hwnd 然后我需要根据它们是什么将每个案例转换为一个 int。我有工作扩展方法来做到这一点,但我需要先找到哪个是哪个

标签: c# regex numbers words roman-numerals


【解决方案1】:

由于您已经有了解析器,如果给定一些表面上看起来像有效的罗马/文本输入但实际上不是的东西,它们有望优雅地失败,您可以将它们全部调用并查看哪个通过。

如果您不只是想全部调用它们,则此正则表达式应确定将每个输入传递给哪个解析器。

var re = new Regex(
    @"CHAPTER (?:(?<arabic>\d+)|(?<roman>[IVXLCDM]+)|(?<text>[A-Z ]+))");

例如称为

var input = @"CHAPTER 1
CHAPTER 2
CHAPTER THREE
CHAPTER IV
CHAPTER TWENTY TWO";

foreach (Match match in re.Matches(input))
{
    if (match.Groups["arabic"].Success)
    {
        Console.WriteLine("Pass {0} to Arabic parser", match.Groups["arabic"].Value);
    }
    else if (match.Groups["roman"].Success)
    {
        Console.WriteLine("Pass {0} to Roman parser", match.Groups["roman"].Value);
    }
    else if (match.Groups["text"].Success)
    {
        Console.WriteLine("Pass {0} to Text parser", match.Groups["text"].Value);
    }
}

结果

Pass 1 to Arabic parser
Pass 2 to Arabic parser
Pass THREE to Text parser
Pass IV to Roman parser
Pass TWENTY TWO to Text parser

【讨论】:

    【解决方案2】:

    罗马数字的正则表达式是:\bM{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\b
    数字正则表达式:\d+
    文字的正则表达式:[a-z ]+

    将所有这些组合在:

    CHAPTER (?:(?<digits>\d+)|(?<roman>\bM{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\b)|(?<literal>[A-Z ]+))
    

    【讨论】:

      【解决方案3】:
      CHAPTER (?:\d+|(?:XVIII|XVII|XIII|VIII|XIV|XVI|XII|III|VII|XV|VI|IV|XI|IX|XX|III|II|X|V|I)|(?:(?P<d>TWENTY|THIRTY|FORTY|FIFTY|SIXTY|SEVENTY|EIGHTY|NINETY)?(?(d)(?: (?:ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT|NINE))?|(?:ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT|NINE|TEN|ELEVEN|TWELVE|THIRTEEN|FOURTEEN|FIFTEEN|SIXTEEN|SEVENTEEN|EIGTHEEN|NINETEEN))))
      

      细目及说明:

      CHAPTER // match "CHAPTER " literally
          (?:// then either:
              \d+// 1: digits
              |
              (?:// or 2: roman numerals (up to 18) (note: make sure to order them by length!)
                  XVIII|XVII|XIII|VIII|XIV|XVI|XII|III|VII|XV|VI|IV|XI|IX|XX|III|II|X|V|I
              )
              |// or 3: words
              (?:
                  (?P<d>// first, one of the literals "TWENTY", "THIRTY", etc...
                      TWENTY|THIRTY|FORTY|FIFTY|SIXTY|SEVENTY|EIGHTY|NINETY
                  )?// ...if possible
                  (?(d) // then, if the previous group matched...
                      (?: // ...a space...
                          (?:// ...and the numbers "ONE" to "NINE"
                              ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT|NINE
                          )
                      )?// ...if possible.
                      |
                      (?://otherwise, one of "ONE" to "NINETEEN"
                          ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT|NINE|TEN|ELEVEN|TWELVE|THIRTEEN|FOURTEEN|FIFTEEN|SIXTEEN|SEVENTEEN|EIGTHEEN|NINETEEN
                      )
                  )
              )
          )
      

      Demo.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-08
        • 2010-09-21
        • 1970-01-01
        • 2014-05-24
        • 2022-07-12
        • 1970-01-01
        相关资源
        最近更新 更多