Regex 如何编写排除而不是匹配的正则表达式,例如not(这个|字符串)?

Regex 如何编写排除而不是匹配的正则表达式,例如not(这个|字符串)?,regex,emacs,elisp,regex-negation,regex-group,Regex,Emacs,Elisp,Regex Negation,Regex Group,我在尝试创建排除组的Emacs正则表达式时遇到了麻烦[^]排除集合中的单个字符,但我想排除特定的字符序列:类似于[^(not | this)],因此包含“not”或“this”的字符串不匹配 原则上,我可以写([^n][^o][^t]|[^…]),但还有其他更干净的方法吗?这不容易做到。正则表达式是为了匹配事物而设计的,这就是它们所能做的 首先:[^]不指定“排除组”,它指定一个否定字符类。字符类不支持任何形式或形状的分组。它们支持单个字符(为了方便起见,还支持字符范围)。就正则表达式引擎而言,

我在尝试创建排除组的Emacs正则表达式时遇到了麻烦
[^]
排除集合中的单个字符,但我想排除特定的字符序列:类似于
[^(not | this)]
,因此包含“not”或“this”的字符串不匹配


原则上,我可以写
([^n][^o][^t]|[^…])
,但还有其他更干净的方法吗?

这不容易做到。正则表达式是为了匹配事物而设计的,这就是它们所能做的

首先:
[^]
不指定“排除组”,它指定一个否定字符类。字符类不支持任何形式或形状的分组。它们支持单个字符(为了方便起见,还支持字符范围)。就正则表达式引擎而言,您的try
[^(而不是| this)]
[^)(| hinots]
是100%等价的

有三种方法可以解决这种情况:

  • 匹配
    (而不是| this)
    并在您所在环境的帮助下排除任何匹配(否定匹配结果)
  • 如果您的正则表达式引擎支持并且在这种情况下可行,请使用“消极前瞻”
  • 重写表达式以使其匹配:请参见

  • 首先:
    [^n][^o][^t]
    不是解决方案。这也会排除像
    nil
    [^n]
    不匹配)、
    bob
    [^o]
    不匹配)或
    cat
    [^t]
    不匹配)这样的词

    但是,可以使用基本语法构建一个正则表达式,该正则表达式不匹配既不包含
    not
    也不包含
    this
    的字符串:

    ^([^nt]|n($|[^o]|o($|[^t]))|t($|[^h]|h($|[^i]|i($|[^s]))))*$
    

    这个正则表达式的模式是允许任何字符不是单词的第一个字符,或者只允许单词的前缀,而不是整个单词。

    试试M-x齐平线。

    很难相信接受的答案(来自Gumbo)事实上被接受了!除非它被接受了,因为它表明你不能做你想做的事情。除非你有一个函数生成这样的正则表达式(如Gumbo所示),否则编写它们将是一件非常痛苦的事情

    真正的用例是什么——你真正想做什么

    正如Tomalak所指出的,(a)这不是regexps所做的;(b)查看他链接到的另一篇文章,以获得一个好的解释,包括如何解决您的问题

    答案是使用regexp匹配您不需要的内容,然后从初始域中减去该内容。注意,不要试图让regexp进行排除(它不能);在使用regexp匹配您要排除的内容后进行排除


    这就是每个使用regexp的工具的工作原理(例如,
    grep
    ):它们提供了一个单独的选项(例如通过语法)来执行减法——在匹配需要减法的内容之后。

    听起来像是在尝试进行负向前瞻。也就是说,一旦到达某个分隔符,就试图停止匹配

    Emacs不直接支持前瞻,但它支持*、+、和?运算符(*?、+?、?)的非贪婪版本,在大多数情况下,这些运算符可以用于相同的目的

    例如,要匹配此javascript函数的主体:

    bar = function (args) {
        if (blah) {
            foo();
        }
    };
    
    您可以使用以下emacs正则表达式:

    function ([^)]+) {[[:ascii:]]+?};
    
    在这里,一旦我们找到两个元素序列“};”[[:ascii:]]被用于“.”操作符的instad,因为它可以在多行上工作

    这与负向前看有点不同,因为它匹配的};序列本身,但是如果您的目标是提取到该点之前的所有内容,那么您只需使用捕获组\(and\)

    请参阅emacs regex手册:


    作为补充说明,如果您编写任何类型的emacs正则表达式,请务必调用M-x re builder,这将提供一个小IDE,用于针对当前缓冲区编写正则表达式。

    对于匹配字符串进行逻辑测试的用例,我执行以下操作:

    ;; Code to match string ends with '-region' but excludes those that has 'mouse'.
    M-x ielm RET
    *** Welcome to IELM ***  Type (describe-mode) for help.
    ELISP> (setq str1 "mouse-drag-region" str2 "mou-drag-region" str3 "mou-region-drag")
    "mou-region-drag"
    ELISP> (and (string-match-p "-region$" str1) (not (string-match-p "mouse" str1)))
    nil
    ELISP> (and (string-match-p "-region$" str2) (not (string-match-p "mouse" str2))) 
    t
    ELISP> (and (string-match-p "-region$" str3) (not (string-match-p "mouse" str3)))
    nil
    

    我使用这种方法来避免我所讨论的函数的错误:

    如果您试图使用正则表达式查找或替换缓冲区中的文本,您可以使用它


    Visual regexp类固醇允许您使用python regex替换、搜索等。python regex支持负向前看和负向后看。

    我的问题是如何将否定的regexp传递到
    删除行
    解决方案是传递regexp M-x
    保留行

    @Gumbo。您说得对,谢谢单击“regex negation”标签来查看一些类似的问题。有一个补丁(不接受)用于前瞻性断言,它使这成为可能:+1,如果我曾经尝试切换到Emacs,这将是不切换到Emacs的理由。没有lookaheads,任何人怎么能生活呢?:PBeen非常喜欢Emacs,到目前为止,这是我的第一个“什么。。。“我想知道为什么这个答案的投票率如此之低,这是这里最清楚的答案!@Yagamy,因为它或多或少说“不起作用”,但显然有办法让它起作用(尽管这是一个不切实际的办法,更像是最后的手段)。我在这里没有看到“不起作用”的说法。”,甚至相反:你展示了三种解决问题的方法,而第三种方法和公认的答案一样。@Yagamy是真的,但是耍了一个“魔术”这比一个警告性的答案更令人印象深刻。这并不是要减少被接受的答案,这样做有时是唯一的选择,但大多数时候都非常笨拙。我最后提到这个选项是有原因的。我想人们更喜欢有惊喜效果的答案。:)这是一个非常好的答案,因为它有助于以更容易解决的方式理解问题。在emacs中,尝试
    M
    +
    X
    保留行
    以删除与所需内容不匹配的行。欢迎使用stackoverflow。请在您的答案中包括所有关键细节。如书面所示,如果外部链接发生变化,您的答案将没有什么价值。有关更多详细信息,请参阅。