Проблема в том, что подразумевается под "регулярным выражением". Википедия обладает хорошей информацией по этому вопросу, но простое резюме состоит в том, что обычный язык - это язык, определенный с помощью нескольких простых операций, включая буквальное совпадение, чередование и звезду Клини (соответствует нулю или больше). В библиотеки Regex добавлены функции, которые не расширяют этот язык, но упрощают его использование (например, возможность сказать [a-z]
вместо (a|b|c|d|e|f...|z)
).
Затем пришло Perl, в котором реализована поддержка регулярных выражений. Однако вместо использования обычно используемой реализации NFA / DFA для регулярных выражений он реализовал их с помощью обратного отслеживания. Это имеет два следствия: во-первых, оно позволяет добавлять вещи, выходящие за рамки обычных языков, такие как обратное отслеживание, и два, это может быть очень, очень медленным.
Многие языки используют эти реализации регулярных выражений для обратного отслеживания, но было несколько недавнее возрождение удаления функций из выражений, которые затрудняют их эффективную реализацию, в частности, возврат. Go сделал это, библиотека Re2 является реализацией этого на C / C ++. И, как вы обнаружили, ящик регулярных выражений также работает таким образом. Преимущество в том, что оно всегда совпадает по линейному времени.
Для вашего конкретного примера то, что вы пытаетесь сопоставить, действительно все еще является обычным языком, просто его нужно выражать по-другому. Давайте начнем с простой части, сопоставляя символы, но не допуская последовательных точек. Вместо того, чтобы думать об этом таким образом, думайте о том, что он соответствует, возможно, точке между символами, но сами символы не являются вариантами. Другими словами, мы можем сопоставить с: [a-z0-9](\.?[a-z0-9])*
. Сначала мы сопоставляем один символ. Если вы хотите, чтобы это начиналось с точки, вы можете удалить эту часть. Затем нам нужно ноль или более вхождений необязательной точки, за которой следует один не точечный символ. Вы можете добавить \.?
, если хотите разрешить точку в конце.
Второе требование, состоящее из 3-30 символов, усложнит это регулярное выражение, поскольку наша повторяющаяся последовательность состоит из 1 или 2 символов. , Я бы предложил вместо этого просто проверить длину программно в дополнение к проверке регулярных выражений. Вы также можете сделать второе регулярное выражение, которое проверяет длину и проверяет, совпадают ли оба (на обычных языках нет операции and).
Вы также можете найти, в зависимости от того, как вы подходите, вам может потребоваться Привязать матч (поставить ^
в начале и $
в конце).
Решение полной проблемы :
use regex::Regex; // 1.3.5
fn main() {
let pat = Regex::new(r"^[a-z0-9](\.?[a-z0-9])*$").unwrap();
let names = &[
"valid123",
"va.li.d.12.3",
".invalid",
"invalid.",
"double..dot",
"ss",
"really.long.name.that.is.too.long",
];
for name in names {
let len = name.len();
let valid = pat.is_match(name) && len >= 3 && len <= 30;
println!("{:?}: {:?}", name, valid);
}
}