14.2 何为单词或符号的组成部分?

Emacs将不同的字符视为属于不同的语法类别。例如,正则表达式‘\\w+’是一个模式,指定一个或多个单词组成字符。单词组成字符属于一个语法类别。其他语法类别包括标点字符类,如句点和逗号,以及空白字符类,如空格和制表符。(更多信息,请参阅see Syntax Tables in The GNU Emacs Lisp Reference Manual。)

语法表指定哪些字符属于哪些类别。通常,连字符不被指定为单词组成字符。相反,它被指定为符号名称中的字符类,但不是单词。这意味着count-words-example函数以与单词间空格相同的方式处理它,这就是为什么count-words-example将‘multiply-by-seven’计为三个单词的原因。

有两种方法可以使Emacs将‘multiply-by-seven’计为一个符号:修改语法表或修改正则表达式。

我们可以通过修改Emacs为每种模式保留的语法表来重新定义连字符为单词组成字符。这个动作将满足我们的目的,除了连字符仅仅是符号中最常见的不是单词组成字符的字符;还有其他字符。

或者,我们可以重新定义count-words-example定义中使用的正则表达式,以包括符号。这个过程具有清晰的优点,但任务有点棘手。

第一部分相当简单:模式必须匹配至少一个是单词或符号组成字符的字符。因此:

"\\(\\w\\|\\s_\\)+"

\\(’是包含‘\\w’和‘\\s_’作为选择项的分组结构的第一部分,由‘\\|’分隔。‘\\w’匹配任何单词组成字符,而‘\\s_’匹配任何是符号名称但不是单词组成字符的字符。组后面的‘+’表示单词或符号组成字符必须至少匹配一次。

然而,正则表达式的第二部分设计更难。我们希望第一部分后面可以选择跟随零个或多个不是单词或符号组成字符的字符。起初,我认为可以用以下方式定义这个:

"\\(\\W\\|\\S_\\)*"

大写的‘W’和‘S’匹配不是单词或符号组成字符的字符。不幸的是,这个表达式匹配任何不是单词组成字符或符号组成字符的字符。这匹配任何字符!

我然后注意到我的测试区域中的每个单词或符号后面都跟着空白(空格、制表符或换行符)。所以我尝试在匹配一个或多个单词或符号组成字符的模式之后放置一个匹配一个或多个空格的模式。这也失败了。单词和符号通常由空白分隔,但在实际代码中,括号可能跟随符号,标点可能跟随单词。因此最后,我设计了一个模式,其中单词或符号组成字符后面可以选择跟随不是空白字符的字符,然后可以选择跟随空白字符。

以下是完整的正则表达式:

"\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"