Избегайте повторяющихся элементов в разделенном запятыми списке двухбуквенных слов - PullRequest
2 голосов
/ 14 марта 2020

Мне нужно написать регулярное выражение, которое допускает группу из 2 символов только один раз. Это мое текущее регулярное выражение:

^([A-Z]{2},)*([A-Z]{2}){1}$

Это позволяет мне проверить что-то вроде этого:

AL,RA,IS,GD
AL
AL,RA

Проблема в том, что он также проверяет AL,AL и AL,RA,AL.

РЕДАКТИРОВАТЬ

Здесь есть более подробная информация.

Что разрешено:

AL,RA,GD
AL
AL,RA
AL,IS,GD

Что не должно быть разрешено:

AL,RA,AL
AL,AL
AL,RA,RA
AL,IS,AL
IS,IS,AL
IS,GD,GD
IS,GD,IS

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

Ответы [ 3 ]

3 голосов
/ 14 марта 2020

Прежде всего, давайте сократим ваш шаблон. Этого легко достичь, поскольку длина каждого элемента, разделенного запятыми, фиксирована, а элементы списка состоят только из прописных букв ASCII. Итак, ваш шаблон может быть записан как ^(?:[A-Z]{2}(?:,\b)?)+$. См. эту демонстрацию регулярных выражений .

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

^(?!.*\b([A-Z]{2})\b.*\b\1\b)(?:[A-Z]{2}(?:,\b)?)+$

См. Демонстрационную версию regex

Возможная реализация в Swift :

func isValidInput(Input:String) -> Bool {
    return Input.range(of: #"^(?!.*\b([A-Z]{2})\b.*\b\1\b)(?:[A-Z]{2}(?:,\b)?)+$"#, options: .regularExpression) != nil
}

print(isValidInput(Input:"AL,RA,GD")) // true
print(isValidInput(Input:"AL,RA,AL")) // false

Подробности

  • ^ - начало строки
  • (?!.*\b([A-Z]{2})\b.*\b\1\b) - отрицательный прогноз, который не дает совпадения, если непосредственно справа от текущего местоположения есть:
    • .* - любые 0+ символов, кроме символов перевода строки, как можно больше
    • \b([A-Z]{2})\b - двухбуквенное слово как целое слово
    • .* - любые 0+ символов, кроме символов разрыва строки, как можно больше
    • \b\1\b - то же самое слово, что и в группе 1. ПРИМЕЧАНИЕ : границы слов здесь не являются необходимо в текущем сценарии, где длина слова фиксирована, это два, но если вы не знаете длину слова и у вас есть [A-Z]+, вам понадобятся границы слова или другие границы в зависимости от ситуации
  • (?:[A-Z]{2}(?:,\b)?)+ - 1 или более последовательностей:
    • [A-Z]{2} - две заглавные буквы ASCII
    • (?:,\b)? - необязательная последовательность: , только если сопровождается словом char: letter, di git или _. Это гарантирует, что , не будет разрешено в конце строки
  • $ - конец строки.
3 голосов
/ 14 марта 2020

Попробуйте что-то наподобие этого выражения:

/^(?:,?(\b\w{2}\b)(?!.*\1))+$/gm

У меня нет знания о Свифте, поэтому возьмите его с крошкой соли. Идея в основном состоит в том, чтобы сопоставлять только целую строку, при этом следя за тем, чтобы ни одна сопоставленная группа не встречалась в более поздней точке строки.

1 голос
/ 14 марта 2020

Вы можете использовать отрицательный прогноз с обратной ссылкой:

^(?!.*([A-Z]{2}).*\1).*

, если, как и во всех примерах в вопросе, известно, что строка содержит только разделенные запятыми пары прописных письма. Я ослаблю это предположение позже в своем ответе.

Демонстрация

Регулярное выражение выполняет следующие операции:

^             # match beginning of line
(?!           # begin negative lookahead
  .*          # match 0+ characters (1+ OK)
  ([A-Z]{2})  # match 2 uppercase letters in capture group 1
  .*          # match 0+ characters (1+ OK)
  \1          # match the contents of capture group 1
)             # end negative lookahead
.*            # match 0+ characters (the entire string)

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

^(?=[A-Z]+(?:,[A-Z]+)*$)(?!.*(?:^|,)([A-Z]{2}),(?:.*,)?\1(?:,|$)).*

Демо

Регулярное выражение выполняет следующие операции:

^             # match beginning of line
(?=           # begin pos lookahead
  [A-Z]+      # match 1+ uc letters
  (?:,[A-Z]+) # match ',' then by 1+ uc letters in a non-cap grp
  *           # execute the non-cap grp 0+ times
  $           # match the end of the line
)             # end pos lookahead
(?!           # begin neg lookahead
  .*          # match 0+ chars
  (?:^|,)     # match beginning of line or ','
  ([A-Z]{2})  # match 2 uc letters in cap grp 1
  ,           # match ','
  (?:.*,)     # match 0+ chars, then ',' in non-cap group
  ?           # optionally match non-cap grp
  \1          # match the contents of cap grp 1
  (?:,|$)     # match ',' or end of line
)             # end neg lookahead
.*            # match 0+ chars (entire string)

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

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