Существует ли альтернативный синтаксис регулярных выражений, чтобы избежать ошибки "просмотр, включая просмотр и просмотр, не поддерживается"? - PullRequest
0 голосов
/ 28 апреля 2020

Я попытался реализовать это регулярное выражение для проверки, имеет ли строка ("username") длину от 3 до 30, содержит только буквы (az), цифры (0-9) и точки (.) (Не подряд ):

use regex::Regex; // 1.3.5

fn main() {
    Regex::new(r"^(?=.{3,30}$)(?!\.)(?!.*\.$)(?!.*?\.\.)[a-z0-9.]+$").unwrap();
}

При попытке скомпилировать регулярное выражение я получаю эту ошибку:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
regex parse error:
   r"^(?=.{3,30}$)(?!\.)(?!.*\.$)(?!.*?\.\.)[a-z0-9.]+$").unwrap();
     ^^^
error: look-around, including look-ahead and look-behind, is not supported
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

Я мог бы удалить длину {3,30} и получить длину строки, как было предложено, но для второй части (?!\.)(?!.*\.$)(?!.*?\.\.)[a-z0-9.]+$ (не допускать последовательных точек)?

1 Ответ

3 голосов
/ 28 апреля 2020

Проблема в том, что подразумевается под "регулярным выражением". Википедия обладает хорошей информацией по этому вопросу, но простое резюме состоит в том, что обычный язык - это язык, определенный с помощью нескольких простых операций, включая буквальное совпадение, чередование и звезду Клини (соответствует нулю или больше). В библиотеки 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...