在 emacs 中转义正则表达式需要多少个反斜杠? “定制”模式?
我正在尝试使用 emacs 的 customize-group
包来调整我的设置的某些部分,但我遇到了困难。在使用自定义进行更改后,我在 .emacs 文件中看到类似的内容:
'(tramp-backup-directory-alist (quote (("\\\\`.*\\\\'" . "~/.emacs.d/autobackups"))))
这是将以下内容放入自定义文本字段的结果:
Regexp matching filename: \\`.*\\'
这是一个代表性示例:我实际上正在尝试更改一些需要正则表达式的内容,并且它们都表现出同样的问题。到底有多少层引用?我似乎无法找到神奇的反斜杠数量来让天哪做我要求的事情,即使对于像 .*
这样最简单的正则表达式也是如此。现在,给定的定制不会产生任何结果。它不会改变 emacs 的默认行为。
更好的是,这到底是在哪里记录的?在 Google 上搜索有点困难,但我已经在其中以及官方文档和 Emacs wiki 中尝试了很多东西。哪里有权威来源可以说明需要多少个反斜杠才能在自定义模式下使正则表达式真正起作用 - 或者至少以某种警告失败而不是默默地失败?
编辑:正如愤怒地提出问题时经常发生的那样,我问了错误的问题。幸运的是,下面的答案让我找到了我需要的问题的答案,即关于引用规则。我将尝试写下我在这里学到的东西,因为我发现文档和 Google 资源对此非常晦涩难懂。以下是我通过反复试验发现的引用规则,我希望它们可以帮助其他人,启发纠正,或两者兼而有之。
当 emacs 自定义模式缓冲区要求您提供“正则表达式匹配文件名”时,正如 emacs 经常所做的那样,它既简洁又独特(经常创作者的个性被赋予创作!)。一方面,这意味着正则表达式将与文件的整个路径进行比较以搜索匹配项,而不仅仅是与文件本身的名称进行比较,就像您从术语“中假设的那样”文件名”。例如,这与 emacs 的 buffer-file-name
函数中使用的“文件名”含义相同。
此外,虽然如果您将 foo
放入字段中,您会看到 "foo"
(带双引号)写入实际文件,但这还不够引用,也不是正确的引用。您需要使用据我所知只有 emacs 使用的引用样式来引用正则表达式:“backtick-foo-single-quote”方案。然后你需要转义它,使其成为\`backslash-backtick-foo-backslash-single-quote\'
(如果你认为输入很头疼) Markdown,在 emacs 中更是如此)。
最重要的是,emacs 似乎有一个规则,即 .
正则表达式特殊字符与文件名开头的 /
不匹配,所以,就像上面发生在我身上的那样,经典的 .*
模式似乎不匹配任何内容:要匹配“所有文件”,您实际上需要正则表达式 /.*
,然后将其填充到引用格式中定制模式来生产\`/.*\'
,之后customize 在其上绘制另一 转义层并将其写入自定义文件。
我的一项努力的最终结果 - 设置 #autosave# 文件不会弄乱你正在工作的目录,而是全部存在于一个地方:
(custom-set variables
'(auto-save-file-name-transforms (quote (
("\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'" "~/.emacs.d/autobackups/\\2" t)
("\\`/.*/\\(.*?\\)\\'" "~/.emacs.d/autobackups/\\1" t)
))))
elisp 中的反斜杠对你的理智的威胁要大得多括号。
编辑2:我又犯错了。我终于找到了相关文档(通过阅读另一个堆栈溢出问题< /a>,当然!):正则表达式反斜杠构造。让我困惑的关键点:反引号和单引号在这种情况下不引用:它们相当于perl的^
和$
特殊字符。反斜杠反引号构造匹配锚定在正在检查匹配的字符串开头的空字符串,反斜杠单引号构造匹配正在考虑的字符串末尾的空字符串。所谓“正在考虑的字符串”,我的意思是“缓冲区,在这种情况下它恰好只包含一个文件路径,但是如果你想要匹配,你需要匹配整个该死的东西,因为这是 elisp 的全局正则表达式行为”。
对天发誓,这就像对付外星文明一样。
编辑 3:为了避免将来的读者感到困惑 -
\`
是 emacs 正则表达式,表示“缓冲区的开头”。 (cf Perl 的\A
)\'
是 emacs 正则表达式,表示“缓冲区末尾”。 (参见 Perl 的\Z
)^
是表示“行的开头”的常见习语正则表达式。它可以在 emacs 中使用。$
是表示“行尾”的常用习语正则表达式。它可以在 emacs 中使用。
由于跨多行文本正文的正则表达式搜索在 emacs 中比其他地方更常见(例如 Mx 发生
),因此 emacs 中使用反引号和单引号特殊字符,据我所知, ,它们在自定义模式的上下文中使用,因为如果您正在考虑自定义模式字段的通用未知输入,它可能包含换行符,因此您需要使用缓冲区的开头和缓冲区的结尾因为开头有特殊字符输入的结尾不能保证是行的开头和结尾。
我不确定是否会后悔劫持我自己的 Stack Overflow 问题并将其本质上变成一篇博文。
I'm trying to use emacs' customize-group
packages to tweak some parts of my setup, and I'm stymied. I see things like this in my .emacs file after I make changes with customize:
'(tramp-backup-directory-alist (quote (("\\\\`.*\\\\'" . "~/.emacs.d/autobackups"))))
This was the result of putting the following into the customize text field:
Regexp matching filename: \\`.*\\'
This is a representative sample: I'm actually trying to change several things that want a regexp, and they all show this same problem. How many layers of quoting are there, really? I can't seem to find the magic number of backslashes to get the gosh-dang thing to do what I'm asking it to, even for the simplest regular expressions like .*
. Right now, the given customization produces - nothing. It makes no change from emacs' default behavior.
Better yet, where on earth is this documented? It's a little difficult to Google for, but I've been trying quite a few things there as well as in the official documentation and the Emacs wiki. Where is an authoritative source for how many dang backslashes one needs to make a regular expression in customize-mode actually work - or at the very least, to fail with some kind of warning instead of failing silently?
EDIT: As so often happens with questions asked in anger, I was asking the wrong question. Fortunately the answers below, led me to the answer to the question that I needed, which was about quoting rules. I'm going to try to write down what I learned here, because I find the documentation and Googleable resources to be maddeningly obscure about this. So here are the quoting rules I found by trial and error, and I hope that they help someone else, inspire correction, or both.
When an emacs customize-mode buffer asks you for a "Regexp matching filename", it is being, as emacs often is, both terse and idiosyncratic (how often the creator's personality is imparted to the creation!). It means, for one thing, a regexp that will be compared to the whole path of the file in search of a match, not just to the name of the file itself as you might assume from the term "filename". This is the same sense of "filename" used in emacs' buffer-file-name
function, for example.
Further, although if you put foo
in the field, you'll see "foo"
(with double-quotes) written to the actual file, that's not enough quoting and not the right quoting. You need to quote your regexp with the quoting style that, as far as I can tell, only emacs uses: the ``backtick-foo-single-quote'`scheme. And then you need to escape that, making it \`backslash-backtick-foo-backslash-single-quote\'
(and if you think that's a headache to input in Markdown, it's more so in emacs).
On top of this, emacs appears to have a rule that the .
regexp special character does not match a /
at the beginning of filenames, so, as was happening to me above, the classic .*
pattern will appear to match nothing: to match "all files", you actually need the regexp /.*
, which then you stuff into the quote format of customize-mode to produce \`/.*\'
, after which customize paints another layer of escaping onto it and writes it to the customization file.
The final result for one of my efforts - a setting such that #autosave# files don't gunk up the directory you're working in, but instead all live in one place:
(custom-set variables
'(auto-save-file-name-transforms (quote (
("\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'" "~/.emacs.d/autobackups/\\2" t)
("\\`/.*/\\(.*?\\)\\'" "~/.emacs.d/autobackups/\\1" t)
))))
Backslashes in elisp are a far greater threat to your sanity than parentheses.
EDIT 2: Time for me to be wrong again. I finally found the relevant documentation (through reading another Stack Overflow question, of course!): Regexp Backslash Constructs. The crucial point of confusion for me: the backtick and single quote are not quoting in this context: they're the equivalent of perl's ^
and $
special characters. The backslash-backtick construct matches an empty string anchored at the beginning of the string being checked for a match, and the backslash-single-quote construct matches the empty string at the end of the string-under-consideration. And by "string under consideration," I mean "buffer, which just happens to contain only a file path in this case, but you need to match the whole dang thing if you want a match at all, since this is elisp's global regexp behavior."
Swear to god, it's like dealing with an alien civilization.
EDIT 3: In order to avoid confusing future readers -
\`
is the emacs regex for "the beginning of the buffer." (cf Perl's\A
)\'
is the emacs regex for "the end of the buffer." (cf Perl's\Z
)^
is the common-idiom regex for "the beginning of the line." It can be used in emacs.$
is the common-idiom regex for "the end of the line." It can be used in emacs.
Because regex searches across multi-line bodies of text are more common in emacs than elsewhere (e.g. M-x occur
), the backtick and single-quote special characters are used in emacs, and as best as I can tell, they're used in the context of customize-mode because if you are considering generic unknown input to a customize-mode field, it could contain newlines, and therefore you want to use the beginning-of-buffer and end-of-buffer special characters because the beginning and end of the input are not guaranteed to be the beginning and end of a line.
I am not sure whether to regret hijacking my own Stack Overflow question and essentially turning it into a blog post.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在自定义字段中,您需要根据此处描述的语法输入正则表达式。当customize将正则表达式写入字符串时,正则表达式中的任何反斜杠或双引号字符都将按照常规字符串转义约定进行转义。
简而言之,只需在正则表达式字段中输入单个反斜杠,它们就会在写入
.emacs
的结果custom-set-variables
子句中正确加倍。另外:由于您的正则表达式用于匹配文件名,因此您可以尝试打开一个包含您想要匹配的文件的目录,然后运行
Mx re-builder RET
。然后,您可以以字符串转义格式输入正则表达式,以确认它与这些文件匹配。通过在 dired 缓冲区中输入% m
,您可以输入非转义格式的正则表达式(即,就像在自定义字段中一样),并且 dired 将标记匹配的文件名。In the customize field, you'd enter the regexp according to the syntax described here. When customize writes the regexp into a string, any backslashes or double-quote chars in the regexp will be escaped, as per regular string escaping conventions.
So in short, just enter single backslashes in the regexp field, and they'll get correctly doubled up in the resulting
custom-set-variables
clause written to your.emacs
.Also: since your regexp is for matching filenames, you might try opening up a directory containing files you'd like to match, and then run
M-x re-builder RET
. You can then enter the regexp in string-escaped format to confirm that it matches those files. By typing% m
in a dired buffer, you can enter a regexp in unescaped format (ie. just like in the customize field), and dired will mark matching filenames.