Изменить регулярное выражение для списка чисел и числовых выражений диапазона - PullRequest
1 голос
/ 16 ноября 2009

Я использую ExtJS. Одно из текстовых полей, созданных с помощью компонента ExtJS, должно разрешать разделенные запятыми строки чисел / операторов (3 аналогичных примера), например

1, 2-3, 4..5, <6, <=7, >8, >=9 
>2, 3..5, >=9,>10
<=9, 1, <=8, 4..5, 8-9

Здесь я использую операторы equals, range (-), sequence (..) и больше / равно операторам для чисел, меньших или равных 100. Эти числа разделяются запятой.

Что может быть регулярным выражением для этого типа строки?

По моему ранее заданному вопросу ... Я получил решение от "dlamblin": ^(?:\d+(?:(?:\.\.|-)\d+)?|[<>]=?\d+)(?:,\s*\d+(?:(?:\.\.|-)\d+)?|[<>]=?\d+)*$

Это прекрасно работает для всех моделей, кроме:

  1. Только если операторы отношений (<, <=, >, >=) присутствуют в качестве первого элемента строки. Например. <=3, 4-5, 6, 7..8 отлично работает, но оператор <=3, 4-5, 6, 7..8, >=5 не на 1-м элементе строки.

  2. Также строка <3<4, 5, 9-4 не выдает никакой ошибки, т.е. она удовлетворяет условию, хотя запятая требуется между <3 и <4.

  3. Числа в строке должны быть меньше или равны 100. Т.е. <100, 0-100, 99..100

  4. Он не должен разрешать начальные нули (например, 003, 099)

Ответы [ 4 ]

9 голосов
/ 16 ноября 2009

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

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

2 голосов
/ 16 ноября 2009

Совет Уэлбога использовать токенизатор - нормальный вариант.

Если у вас есть какое-то другое ограничение, которое вызывает регулярное выражение, вы можете использовать

^(<|<=|>|>=)?\s*(100|0|[1-9]\d?)((\.\.|-)(100|0|[1-9]\d?))?(,\s*(<|<=|>|>=)?\s*(100|0|[1-9]\d?)((\.\.|-)(100|0|[1-9]\d?))?)*$

Это результат расширения вручную следующего:

num   = (100|0|[1-9]\d?)
op    = (<|<=|>|>=)
range = op?\s*num((\.\.|-)num)?
expr  = ^range(,\s*range)*$
1 голос
/ 16 ноября 2009

Я согласен с Welbog, что до / постобработка должна быть лучшим выбором.

НО, поскольку мне так нравится RegEx, вот мое решение.

^[ \t]*(?:(?:0|[1-9][0-9]?|100)(?:(?:\-|\.\.)(?:0|[1-9][0-9]?|100))?|(?:[<>]=?)(?:0|[1-9][0-9]?|100))(?:[ \t]*,[ \t]*(?:(?:0|[1-9][0-9]?|100)(?:(?:\-|\.\.)(?:0|[1-9][0-9]?|100))?|(?:[<>]=?)(?:0|[1-9][0-9]?|100)))*[ \t]*$

'\s' не используется, так как может включать в себя '\n' в некоторых движках.

'\d' не используется, так как вам потребуется [1-9], поэтому [0-9] будет проще в использовании.

'(?:0|[1-9][0-9]?|100)' будет соответствовать числу от 0 до 100 без нуля в начале.

'(?:[&lt;&gt;]=?)(?:0|[1-9][0-9]?|100)' будет соответствовать условиям, следующим за числом (если вы также хотите сопоставить '=', просто настройте его).

'(?:0|[1-9][0-9]?|100)(?:(?:\-|\.\.)(?:0|[1-9][0-9]?|100))?' будет соответствовать номеру с необязательным диапазоном или последовательностью.

Полное объяснение:

^
[ \t]*  // Prefix spaces
(?: <i>// A valid term</i>
    <i>// A number</i>
    (?:0|[1-9][0-9]?|100)
    <i>// Optional range or sequence</i>
    (?:
        (?:\-|\.\.)
        (?:0|[1-9][0-9]?|100)
    )?
    |
    <i>// Condition and number</i>
    (?:[<>]=?)(?:0|[1-9][0-9]?|100)
)
(?: <i>// Other terms</i>
    [ \t]*,[ \t]*   // Comma with prefix and suffix spaces
    (?: <i>// A valid term</i>
        <i>// A number</i>
        (?:0|[1-9][0-9]?|100)
        <i>// Optional range or sequence</i>
        (?:
            (?:\-|\.\.)
            (?:0|[1-9][0-9]?|100)
        )?
        |
        <i>// Condition and number</i>
        (?:[<>]=?)(?:0|[1-9][0-9]?|100)
    )
)*
[ \t]*  <i>// Tail spaces</i>

Я тестирую с помощью регулярного поиска Eclipse, и он работает.

Надеюсь, это поможет.

1 голос
/ 16 ноября 2009

Это должно работать:

^(?:(?:\s*((?:\<|\>|\<\=|\>\=)?(?:[1-9]|[1-9]\d|100))\s*(?:,|$))|(?:\s*((?:[1-9]|[1-9]\d|100)(?:\.\.|\-)(?:[1-9]|[1-9]\d|100))\s*(?:,|$)))*$

(Вам, очевидно, потребуется использовать параметр «многострочный».)

Если у вас есть преимущество механизма регулярных выражений, который поддерживает опцию «игнорировать пробелы», то вы можете разбить его следующим образом:

^                           # beginning of line
(?:   
  (?:
    \s*                     # any whitespace
    (                       # capture group
      (?:<|>|<=|>=)?        # inequality
      (?:[1-9]|[1-9]\d|100) # single value
    )
    \s*                     # any whitespace
    (?:,|$)                 # comma or end of line
  )
  |
  (?:
    \s*                     # any whitespace
    (                       # catpure group
      (?:[1-9]|[1-9]\d|100) # single value
      (?:\.\.|\-)           # range modifier
      (?:[1-9]|[1-9]\d|100) # single value
    )
    \s*                     # any whitespace
    (?:,|$)                 # comma or end of line
  )
)+                          # one or more of all this
$                           # end of line

Как видите, он соответствует вашим примерам в Expresso:

http://imgur.com/5ctQS.png

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