32

我很难创建一个排除组的 Emacs 正则表达式。[^]排除集合中的单个字符,但我想排除特定的字符序列:类似[^(not|this)],以便包含“not”或“this”的字符串不匹配。

原则上,我可以写([^n][^o][^t]|[^...]),但还有另一种更清洁的方法吗?

4

8 回答 8

30

这不容易。正则表达式旨在匹配事物,这就是它们所能做的。

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

三种方法可以摆脱这种情况:

  1. 在您所在的环境的帮助下匹配(not|this)排除任何匹配项(否定匹配结果)
  2. 如果您的正则表达式引擎支持并且在这种情况下可行,请使用负前瞻
  3. 重写表达式,使其可以匹配:查看我之前提出的类似问题
于 2010-02-07T19:28:38.263 回答
19

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

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

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

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

于 2010-02-07T19:52:43.550 回答
14

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

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

正如 Tomalak 所指出的,(a)这不是正则表达式的作用;(b) 查看他链接到的另一篇文章,以获得很好的解释,包括如何处理您的问题。

答案是使用正则表达式来匹配您想要的内容,然后从初始域中减去它。IOW,不要试图让正则表达式进行排除(它不能);在使用正则表达式匹配您要排除的内容执行排除。

这就是每个使用正则表达式的工具的工作方式(例如,grep):它们提供了一个单独的选项(例如通过语法)来执行减法 - 在匹配需要减去的内容之后。

于 2011-08-21T21:56:45.160 回答
10

听起来您正在尝试进行负前瞻。即,一旦到达某个分隔符,您就会尝试停止匹配。

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

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

bar = function (args) {
    if (blah) {
        foo();
    }
};

您可以使用这个 emacs 正则表达式:

function ([^)]+) {[[:ascii:]]+?};

一旦我们找到两个元素序列“};”,我们就停止了。[[:ascii:]] 用于代替“。” 运算符,因为它适用于多行。

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

请参阅 emacs 正则表达式手册:http ://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html

附带说明一下,如果您编写任何类型的 emacs 正则表达式,请务必调用 Mx re-builder,这将打开一个小 IDE,用于针对当前缓冲区编写您的正则表达式。

于 2013-03-30T03:09:47.547 回答
6

试试 Mx 冲洗线。

于 2010-02-07T23:47:48.163 回答
2

对于为逻辑测试匹配字符串的用例,我这样做:

;; 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

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

于 2015-08-03T21:06:08.227 回答
0

如果您尝试使用正则表达式查找或替换缓冲区中的文本,您可以使用https://github.com/benma/visual-regexp-steroids.el/

Visual regexp steroids 允许您使用 python regex 进行替换、搜索等。Python 正则表达式支持负前瞻和负后瞻。

于 2020-05-11T16:52:58.173 回答
0

我的问题是如何将否定的正则表达式传递给delete-lines解决方案是传递正则表达式 Mxkeep-lines

于 2021-04-06T14:48:47.587 回答