.NET Regex захватывает не в ожидаемом порядке - PullRequest
5 голосов
/ 21 августа 2010

В .NET, регулярное выражение не организует захваты, как я ожидал. (Я не буду называть это ошибкой, потому что, очевидно, кто-то это намеревался. Однако я не ожидал, что это сработает, и не считаю это полезным).

Это регулярное выражение для ингредиентов рецепта (упрощенно для примера):

(?<measurement>           # begin group
  \s*                     # optional beginning space or group separator
  (
    (?<integer>\d+)|      # integer
    (
      (?<numtor>\d+)      # numerator
      /
      (?<dentor>[1-9]\d*) # denominator. 0 not allowed
    )
  )
  \s(?<unit>[a-zA-Z]+)
)+                        # end group. can have multiple

Моя строка: 3 tbsp 1/2 tsp

Результирующие группы и захваты:

[измерение] [0] = 3 столовые ложки
[измерение] [ 1 ] = 1/2 чайной ложки
[целое число] [0] = 3
[numtor] [ 0 ] = 1
[dentor] [ 0 ] = 2
[единица измерения] [0] = столовая ложка
[Единица измерения] [ 1 ] = ч.л

Обратите внимание, что хотя 1/2 tsp находится во 2-м захвате, его части находятся в [0], поскольку эти места ранее не использовались.

Есть ли способ получить все части с предсказуемыми полезными индексами без необходимости повторного запуска каждой группы через регулярное выражение?

Ответы [ 3 ]

1 голос
/ 21 августа 2010

Есть ли способ получить все части с предсказуемыми полезными индексами без необходимости повторного запуска каждой группы через регулярное выражение?

Не с захватами. И если вы все равно собираетесь выполнить несколько совпадений, я предлагаю вам удалить + и сопоставить каждый компонент измерения отдельно, например, так:

  string s = @"3 tbsp 1/2 tsp";

  Regex r = new Regex(@"\G\s* # anchor to end of previous match
    (?<measurement>           # begin group
      (
        (?<integer>\d+)       # integer
      |
        (
          (?<numtor>\d+)      # numerator
          /
          (?<dentor>[1-9]\d*) # denominator. 0 not allowed
        )
      )
      \s+(?<unit>[a-zA-Z]+)
    )                         # end group.
  ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture);

  foreach (Match m in r.Matches(s))
  {
    for (int i = 1; i < m.Groups.Count; i++)
    {
      Group g = m.Groups[i];
      if (g.Success)
      {
        Console.WriteLine("[{0}] = {1}", r.GroupNameFromNumber(i), g.Value);
      }
    }
    Console.WriteLine("");
  }

выход:

[measurement] = 3 tbsp
[integer] = 3
[unit] = tbsp

[measurement] = 1/2 tsp
[numtor] = 1
[dentor] = 2
[unit] = tsp

\G в начале гарантирует, что совпадения происходят только в точке, где закончилось предыдущее совпадение (или в начале ввода, если это первая попытка сопоставления). Вы также можете сохранить позицию конца совпадения между вызовами, а затем использовать метод Matches с двумя аргументами для возобновления синтаксического анализа в той же точке (как если бы это действительно начало ввода).

1 голос
/ 21 августа 2010

Похоже, вам, вероятно, нужно циклически проходить через вход, сопоставляя одно измерение за раз.Тогда у вас будет предсказуемый доступ к частям этого измерения во время итерации цикла для этого измерения.

0 голосов
/ 21 августа 2010

Взглянув на это ... вот несколько предложений, которые могут помочь улучшить регулярное выражение

(?<measurement>           # begin group
  \s*                     # optional beginning space or group separator
  (
    (?<integer>\d+)\.?|   # integer
    (
      (?<numtor>\d+)      # numerator
      /
      (?<dentor>[1-9]\d*) # denominator. 0 not allowed
    )
  )
  \s(?<unit>[a-zA-Z]+)
)+                        # end group. can have multiple
  • Регулярное выражение ожидает пробел в начале .... послетег измерения ....
  • (?<integer>\d+) Я бы попробовал \s? вместо \., чтобы захватить пробел, поскольку он выходит за пределы полной остановки и будет ожидать, что где-нибудь появится точка остановки..
  • Избегайте /, как это, чтобы сделать его буквальным \/
  • Что такое |разделитель для?это делает две исключительно взаимные части - или «целое», или «numtor» с «dentor» ... эта часть выглядит сбивающей с толку ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...