如何否定整个正则表达式?

问题描述 投票:0回答:6

我有一个正则表达式,例如

(ma|(t){1})
。它匹配
ma
t
,但不匹配
bla

我想否定正则表达式,因此它必须匹配

bla
而不是
ma
t
通过向此正则表达式添加一些内容。我知道我可以写
bla
,但实际的正则表达式更复杂。

regex regex-negation
6个回答
133
投票

使用否定环视:

(?!
pattern
)

积极的环视可用于断言模式匹配。否定环视则相反:它用于断言模式不匹配。有些风格支持断言;有些则支持断言。有些对lookbehind等设置了限制。

正则表达式.info 的链接

另请参阅

更多示例

这些是尝试提出玩具问题的正则表达式解决方案作为练习;如果您想学习使用环视的各种方法(嵌套它们、使用它们捕获等),它们应该具有教育意义:


66
投票

假设您只想禁止与正则表达式完全匹配的字符串(即

mmbla
可以,但
mm
不行),这就是您想要的:

^(?!(?:m{2}|t)$).*$

(?!(?:m{2}|t)$)
是负数 lookahead;它表示“从当前位置开始,接下来的几个字符是 not
mm
t
,后面是字符串的结尾。”开头的起始锚点 (
^
) 确保在字符串的开头应用前瞻。如果成功,
.*
将继续并消耗该字符串。

仅供参考,如果您使用 Java 的

matches()
方法,您实际上并不需要
^
和最后的
$
,但它们不会造成任何伤害。不过,前瞻中的
$
是必需的。


2
投票
\b(?=\w)(?!(ma|(t){1}))\b(\w*)

这是给定的正则表达式。
是找到单词边界。
正向展望 (?=\w) 是为了避免空格。
对原始正则表达式的负面展望是为了防止它的匹配。
最后 (\w*) 是捕获剩下的所有单词。
包含单词的组是第 3 组。
简单的 (?!pattern) 将不起作用,因为任何子字符串都会匹配
简单的 ^(?!(?:m{2}|t)$).*$ 将不起作用,因为它的粒度是整行


0
投票

以下内容适用于 JavaScript:

^(?![\s\S]*ORIGINAL_REGEX_SOURCE)[\s\S]*$

例如,在您的情况下,您的否定正则表达式将是

^(?![\s\S]*(ma|(t){1}))[\s\S]*$

下面的

negate
函数可用于将正则表达式转换为其否定形式:

function negate(regex) {
    return new RegExp(
        String.raw`^(?![\s\S]*${regex.source})[\s\S]*$`,
        regex.flags,
    )
}

const tests = [
    { regex: /(ma|(t){1})/, matches: ['ma', 't'], nonMatches: ['bla'] },
    { regex: /foo/, matches: ['foo'], nonMatches: ['bar'] },
    { regex: /(foo|bar)/, matches: ['foo', 'bar'], nonMatches: ['baz'] },
    { regex: /\d{3}/, matches: ['123', '456', '999'], nonMatches: ['foo'] },
]

for (const { regex, matches, nonMatches } of tests) {
    for (const text of matches) {
        const atStart = `${text} ...`
        const atEnd = `... ${text}`
        const inMiddle = `... ${text} ...`

        check(regex.test(text), `${regex} matches ${JSON.stringify(text)}`)
        check(regex.test(atStart), `${regex} matches ${JSON.stringify(atStart)}`)
        check(regex.test(atEnd), `${regex} matches ${JSON.stringify(atEnd)}`)
        check(regex.test(inMiddle), `${regex} matches ${JSON.stringify(inMiddle)}`)

        const negated = negate(regex)

        check(!negated.test(text), `${negated} doesn't match ${JSON.stringify(text)}`)
        check(!negated.test(atStart), `${negated} doesn't match ${JSON.stringify(atStart)}`)
        check(!negated.test(atEnd), `${negated} doesn't match ${JSON.stringify(atEnd)}`)
        check(!negated.test(inMiddle), `${negated} doesn't match ${JSON.stringify(inMiddle)}`)

        const doubleNegated = negate(negated)

        check(doubleNegated.test(text), `${doubleNegated} matches ${JSON.stringify(text)}`)
        check(doubleNegated.test(atStart), `${doubleNegated} matches ${JSON.stringify(atStart)}`)
        check(doubleNegated.test(atEnd), `${doubleNegated} matches ${JSON.stringify(atEnd)}`)
        check(doubleNegated.test(inMiddle), `${doubleNegated} matches ${JSON.stringify(inMiddle)}`)
    }

    for (const text of nonMatches) {
        const atStart = `${text} ...`
        const atEnd = `... ${text}`
        const inMiddle = `... ${text} ...`

        check(!regex.test(text), `${regex} doesn't match ${JSON.stringify(text)}`)
        check(!regex.test(atStart), `${regex} doesn't match ${JSON.stringify(atStart)}`)
        check(!regex.test(atEnd), `${regex} doesn't match ${JSON.stringify(atEnd)}`)
        check(!regex.test(inMiddle), `${regex} doesn't match ${JSON.stringify(inMiddle)}`)

        const negated = negate(regex)

        check(negated.test(text), `${negated} matches ${JSON.stringify(text)}`)
        check(negated.test(atStart), `${negated} matches ${JSON.stringify(atStart)}`)
        check(negated.test(atEnd), `${negated} matches ${JSON.stringify(atEnd)}`)
        check(negated.test(inMiddle), `${negated} matches ${JSON.stringify(inMiddle)}`)

        const doubleNegated = negate(negated)

        check(!doubleNegated.test(text), `${doubleNegated} doesn't match ${JSON.stringify(text)}`)
        check(!doubleNegated.test(atStart), `${doubleNegated} doesn't match ${JSON.stringify(atStart)}`)
        check(!doubleNegated.test(atEnd), `${doubleNegated} doesn't match ${JSON.stringify(atEnd)}`)
        check(!doubleNegated.test(inMiddle), `${doubleNegated} doesn't match ${JSON.stringify(inMiddle)}`)
    }
}

console.info('Tests passed')

function check(condition, message = 'Condition failed') {
    if (!condition) {
        throw new Error(message)
    }
    console.info(message)
}


-1
投票

这个正则表达式计算你的条件:

^.*(?<!ma|t)$

看看它是如何工作的: https://regex101.com/r/Ryg2FX/1


-2
投票

如果你使用 Laravel,请应用此方法。

Laravel 有一个 not_regex,其中验证的字段必须与给定的正则表达式不匹配;内部使用 PHP

preg_match
函数。

'email' => 'not_regex:/^.+$/i'
© www.soinside.com 2019 - 2024. All rights reserved.