Regex для соответствия, если строка * только * содержит * все * символы из набора символов, плюс необязательный

Я столкнулся с проблемой wee с Java regex. (Должен сказать заранее, я не очень опытен ни в Java, ни в регулярном выражении.)

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

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

Настройка

  • Обязательные символы: | (pipe) и - (тире).

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

  • Необязательный символ: : (двоеточие).

    Строка может содержать двоеточие, но не должна. Это единственный допустимый символ, кроме двух выше.

  • Любые другие символы запрещены.

Ожидаемые результаты

Следующие строки должны работать/не работать:

"------" = false
"||||" = false
"---|---" = true
"|||-|||" = true
"--|-|--|---|||-" = true

... и...

"----:|--|:::|---::|" = true
":::------:::---:---" = false
"|||:|:::::|" = false
"--:::---|:|---G---n" = false

... и т.д..

"Уродливое" решение

Теперь у меня есть решение, которое, похоже, работает на основе qaru.site/info/556894/.... Причина, по которой мне хотелось бы лучше, станет очевидной, когда вы оправились от этого:

if (string.matches("^[(?\\:)?\\|\\-]*(([\\|\\-][(?:\\:)?])|([(?:\\:)?][\\|\\-]))[(?\\:)?\\|\\-]*$") || string.matches("^[(?\\|)?\\-]*(([\\-][(?:\\|)?])|([(?:\\|)?][\\-]))[(?\\|)?\\-]*$")) {

    //do funny stuff with a meaningless string

} else {

   //don't do funny stuff with a meaningless string

}

Разрушение

Первое регулярное выражение

 "^[(?\\:)?\\|\\-]*(([\\|\\-][(?:\\:)?])|([(?:\\:)?][\\|\\-]))[(?\\:)?\\|\\-]*$"

проверяет все три символа

Следующий

"^[(?\\|)?\\-]*(([\\-][(?:\\|)?])|([(?:\\|)?][\\-]))[(?\\|)?\\-]*$"

проверьте только два обязательных.

... Да, я знаю...

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

Вопрос в том, что...

Кто-нибудь знает, как сделать это более простым/более элегантным способом?

Бонусный вопрос: есть одна вещь, которую я не совсем понимаю в регулярных выражениях выше (более одного, но это меня больше всего беспокоит):

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

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

Спасибо всем за чтение (и страдание) через мой вопрос и еще большее спасибо тем, кто отвечает.:)

PS

Я попробовал такие вещи, как ^[\\|\\-(?:\\:)?)]$, но это не обеспечило бы обязательные символы all.

Ответ 1

Используйте регулярное выражение, основанное на просмотре.

^(?=.*\\|)(?=.*-)[-:|]+$

или

^(?=.*\\|)[-:|]*-[-:|]*$

или

^[-:|]*(?:-:*\\||\\|:*-)[-:|]*$

DEMO 1
DEMO 2

  • (?=.*\\|) ожидает как минимум один канал.
  • (?=.*-) ожидает как минимум один дефис.
  • [-:|]+ любой char из списка один или несколько раз.
  • $ Конец строки.

Ответ 2

Вот простой ответ:

(?=.*\|.*-|.*-.*\|)^([-|:]+)$

Это говорит о том, что строка должна иметь '-', за которой следует '|', или '|' за которым следует "-", с нетерпением. Затем строка соответствует только допустимым символам.

Демо: http://fiddle.re/1hnu96

Ответ 3

Вот один без lookbefore и -hind.

 ^[-:|]*\\|[-:|]*-[-:|]*|[-:|]*-[-:|]*\\|[-:|]*$

Это не масштабируется, поэтому решение Avinash должно быть предпочтительным - если ваша система регулярных выражений имеет lookbe *.