Regex 是否有其他正则表达式语法来避免错误“不支持环顾四周,包括向前看和向后看”?

Regex 是否有其他正则表达式语法来避免错误“不支持环顾四周,包括向前看和向后看”?,regex,rust,Regex,Rust,我尝试实现这个正则表达式来检查字符串用户名的长度是否在3到30之间,是否只包含字母a-z、数字0-9和句点。不连续: use regex::Regex; // 1.3.5 fn main() { Regex::new(r"^(?=.{3,30}$)(?!\.)(?!.*\.$)(?!.*?\.\.)[a-z0-9.]+$").unwrap(); } 在尝试编译正则表达式时,出现以下错误: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我尝试实现这个正则表达式来检查字符串用户名的长度是否在3到30之间,是否只包含字母a-z、数字0-9和句点。不连续:

use regex::Regex; // 1.3.5

fn main() {
    Regex::new(r"^(?=.{3,30}$)(?!\.)(?!.*\.$)(?!.*?\.\.)[a-z0-9.]+$").unwrap();
}
在尝试编译正则表达式时,出现以下错误:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 正则表达式分析错误: r^?=.{3,30}$?!\.?!.\.$?!.\。[a-z0-9.]+$展开; ^^^ 错误:不支持环顾四周,包括向前看和向后看 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 是否有替代的正则表达式或方法来验证符合这些要求的字符串


我可以删除长度{3,30}并获得建议的字符串长度,但对于第二部分?!\.?!.\.$?!.\.\。[a-z0-9.]+$protect continued dots?

当前的问题是正则表达式的含义。在这方面有很好的信息,但一个简单的总结是,正则语言是通过一些简单的操作定义的,包括文字匹配、交替和Kleene星形匹配零或更多。正则表达式库增加了一些不扩展这种语言的特性,但使其更易于使用,例如可以说[a-z]而不是a | b | c | d | e | f..z

然后,出现了Perl,它实现了对正则表达式的支持。但是,它没有对正则表达式使用常用的NFA/DFA实现,而是使用回溯来实现它们。这有两个后果,一个是,它允许添加常规语言以外的东西,比如回溯,另一个是,它可能非常非常慢

许多语言都使用这些正则表达式的回溯实现,但最近又出现了从表达式中删除使其难以有效实现的特性的情况,特别是回溯。Go已经做到了这一点,是这个的C/C++实现。而且,正如你所发现的,这个方法也是这样工作的。优点是它总是在线性时间内匹配

对于您的特定示例,您试图匹配的内容实际上仍然是一种常规语言,只需以不同的方式表达即可。让我们从简单的部分开始,匹配字符,但不允许连续点。与其这样想,不如将其视为字符之间的匹配点,但字符本身不是选项。换句话说,我们可以匹配:[a-z0-9]\.?[a-z0-9]*。我们首先匹配一个字符。如果你想让它以一个点开始,你可以删除这个部分。然后,我们需要一个可选点的零次或多次出现,后跟一个非点字符。您可以附加一个\。?如果你想在末尾加一个点

第二个要求是3-30个字符,这使得正则表达式相当复杂,因为我们的重复序列是1或2个字符。我建议,除了检查正则表达式之外,还可以通过编程方式检查长度。您还可以创建第二个正则表达式来检查长度,并检查两种匹配的常规语言是否都没有and操作

你也可能会发现,根据你的匹配方式,你可能需要锚定比赛,在开始时放一个“^”,在结束时放一个$

:


目前的问题是正则表达式的含义。在这方面有很好的信息,但一个简单的总结是,正则语言是通过一些简单的操作定义的,包括文字匹配、交替和Kleene星形匹配零或更多。正则表达式库增加了一些不扩展这种语言的特性,但使其更易于使用,例如可以说[a-z]而不是a | b | c | d | e | f..z

然后,出现了Perl,它实现了对正则表达式的支持。但是,它没有对正则表达式使用常用的NFA/DFA实现,而是使用回溯来实现它们。这有两个后果,一个是,它允许添加常规语言以外的东西,比如回溯,另一个是,它可能非常非常慢

许多语言都使用这些正则表达式的回溯实现,但最近又出现了从表达式中删除使其难以有效实现的特性的情况,特别是回溯。Go已经做到了这一点,是这个的C/C++实现。而且,正如你所发现的,这个方法也是这样工作的。优点是它总是在线性时间内匹配

对于您的特定示例,您试图匹配的内容实际上仍然是一种常规语言,只需以不同的方式表达即可。让我们从简单的部分开始,匹配字符,但不允许连续点。与其这样想,不如将其视为字符之间的匹配点,但字符本身不是选项 . 换句话说,我们可以匹配:[a-z0-9]\.?[a-z0-9]*。我们首先匹配一个字符。如果你想让它以一个点开始,你可以删除这个部分。然后,我们需要一个可选点的零次或多次出现,后跟一个非点字符。您可以附加一个\。?如果你想在末尾加一个点

第二个要求是3-30个字符,这使得正则表达式相当复杂,因为我们的重复序列是1或2个字符。我建议,除了检查正则表达式之外,还可以通过编程方式检查长度。您还可以创建第二个正则表达式来检查长度,并检查两种匹配的常规语言是否都没有and操作

你也可能会发现,根据你的匹配方式,你可能需要锚定比赛,在开始时放一个“^”,在结束时放一个$

:


长度在3到30之间-同样,如果您真的想要拒绝多个点,并且只使用正则表达式,您可以使用其中的两个,第一个^[a-z0-9\.]{3,30}$,第二个regex\.\。并检查第一个匹配,第二个不匹配。但我认为下面我的答案中的解决方案以及长度检查会稍微快一点。但是,这可能更符合您的问题模型。长度在3到30之间-而且,如果您真的想拒绝多个点,并且只使用正则表达式,您可以使用其中两个,第一个^[a-z0-9\.]{3,30}$和第二个正则表达式\.\。并检查第一个匹配,第二个不匹配。但我认为下面我的答案中的解决方案以及长度检查会稍微快一点。但是,这可能与你的问题模型更接近。答案很好!一个小提示:和交集和补码是正则语言上的闭合运算,因此真正的正则表达式引擎可以有and运算符。这很难有效地实施。而且往往很难推理。答案很好!一个小提示:和交集和补码是正则语言上的闭合运算,因此真正的正则表达式引擎可以有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);
    }
}