说明:减号,中划线,dash,在本文中等同;下划线,underscore,等同。“连接符”,泛指连接单词的符号(故意没使用“连字符”/hyphen,因为连字符通常就是中划线/减号)。

计算公式里出现的下划线什么意思(浅说下划线与减号)(1)

下划线在上

直观的差别

计算公式里出现的下划线什么意思(浅说下划线与减号)(2)

下划线在超链接中可读性差

深入的差别

以下划线连接的字符串双击就会全部选中(注),而减号连接的字符串要全选需要用鼠标。所以下划线连接更便利,这是一些同学选择使用下划线的一个理由。

这个差别已经接近下划线和减号的本质差别了,那就是它们在“分词”上的差别。在计算机世界里,下划线的连接通常作为一个“单词”,而减号的连接不是。

注:其实并不是所有软件中都这样。随便试了一个版本的Word, 就不是这样(后面图中有)。

分词的差别

这里的“单词”不是英语的单词(word),计算机世界里我们通常说标识符(identifier)。在标识符里,下划线的地位和26个字母基本无差别,比数字的地位还高一点,因为数字通常不能做首字母。

在主流的正则表达式里,用来表示“单词”的字符,即\w是这样的:[A-Za-z0-9_],也就是大小写字母,数字和下划线。注意,它不包含减号(这里的减号是用来表示范围的)。

所以,在计算机世界里,大家对于"word"所包含的字符的约定基本是一致的:包含下划线,但不包含减号。

基于这个分词原则,除了刚才的双击行为的差别,还会产生很多的差别。

排版的差别

排版的差别主要体现在自动换行时。减号会作为换行时截断的边界,而下划线通常不会。

计算公式里出现的下划线什么意思(浅说下划线与减号)(3)

Word中分词/换行的差别

有些考虑不周的软件,在面对超长的“下划线单词”时,由于不分隔还会造成“溢出”(超出了预期的界面区域)。

计算公式里出现的下划线什么意思(浅说下划线与减号)(4)

Jenkins中下划线超长溢出(上下对比)

搜索的差别

如果你的公司做了一款产品,型号叫作 mycompany_myproduct,假如文档全程都用这个代号,极端点,没有提到mycompany或myproduct这两个单词,那么,对于某些搜索引擎,通过myproduct或mycompany将搜索不到这个页面。

如果型号为mycompany-myproduct,通过mycompany和myproduct,则都是可以搜到的。在做SEO时,更需要考虑这种差异。

据说对于百度,两者的差异比较小;而对于Google,用减号连接则更有优势。毕竟多数人会倾向用 myproduct 的关键字进行搜索。

深入的逻辑

从形式和逻辑组合上,共有4种符号用来区分隔断。

  1. 形式上断开,逻辑上断开:这是全隔断,没有争议地用空格;
  2. 形式上连接,逻辑上断开:姑且称“弱连接”,通常用减号;
  3. 形式上连接,逻辑上连接:姑且称“强连接”,通常用下划线;
  4. 形式上断开,逻辑上连接:这是反人类,容易造成错误。如果要算,中文全角空格勉强可以算一个。但这不是它的本意,它只是一些坑的来源。

所以,真正有意义的组合是前3个。我们可以选择其它符号来表达这3种意思,但从外观及传统上,空格,减号,下划线,这3个符号是比较好的选择。

为什么要用下划线?

最初,我们要用下划线,是因为减号用来表示减法了。my-var 表示变量 my 减去 var;如果一个变量含有多个英语单词,为了区分它们,而你又不想用骆驼命名法MyVar,就要用下划线的my_var。大多数编程语言里都这是这样。

这种对标识符的要求会泛化,比如 Python 里 package 的名字里只能用下划线而不能用减号,从而导致作为模块的文件名不能用减号(但作为一般的不被引用的程序文件还是可以用减号的)。

这种泛化进一步蔓延到了C/C 世界里,比如Google prefer的C 文件名是下划线(尽管可以用减号)。

这种泛化最后可能会蔓延到所有需要连接单词的场景上。毕竟人们更容易接受单一的规则。

可以不用下划线的编程世界

但这不是绝对的。

LISP类语言

在能明确区分操作符和连接符的语法里,标识符就可以包含减号了,比如LISP,操作符是前置的,元素以空格或括号分隔,这样标识符就可以随意包含减号了。

(let ((my-var 300) (your-var 100)) (print (- my-var your-var)))

上面的和下面的代码,结果都是200。"var-300", "var-100", 甚至"300-300", "1-100"都只是标识符而已,不会被当作减法表达式。只有列表里的第一个元素是减号才表示减法操作。

(let ((var-300 300) (var-100 100)) (print (- var-300 var-100))) (let ((300-300 300) (1-100 100)) (print (- 300-300 1-100)))

HTML世界

在XSL中,大量使用带减号的关键字,比如for-each, value-of, copy-of。同样,你自己的标识符当然也可以包含减号,比如下面代码中的my-header。

<xsl:variable name="my-header"> <tr> <th>Title</th> <th>Artist</th> </tr> </xsl:variable> <xsl:template match="/"> <table border="1"> <xsl:copy-of select="$my-header" /> <xsl:for-each select="catalog/cd"> <tr> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="artist"/></td> </tr> </xsl:for-each> </table> </xsl:template>

CSS中也是这样。

.banner { border: solid black 1px; box-shadow: 1px 2px; background-color: yellow; text-align: center; box-sizing: border-box; width: calc(100% - 80px); }

它有专用的关键字用来引用变量的值(var),和做表达式计算(calc),所以它可以肆无忌惮地用减号开头的标识符。

.foo { --widthA: 100px; --widthB: calc(var(--widthA) / 2); --widthC: calc(var(--widthB) / 2); width: var(--widthC); }

一种感觉,在HTML的世界里,似乎很抵触用下划线。HTML/CSS/XML/XSL的关键字里,似乎都是用减号而不是用下划线。

思考:语言只是一种约定吗?

小时候,一些读错的多音字,现在已经变成了正确的。因为大多数人都按照“错误”的在读,比如呆板,曝光,等等。

毕竟,语言的功用是交流,大多数人都能理解才是重要的,既然绝大多数人都认为它应该那么念,“将错就错”也没什么不好。而且,原来的那种“正确”的读音也没有反映出更多或更正确的本质。

我就职的上一家公司,到处都是下划线,比如在Linux内核代码里,如果看到下划线命名的文件,那基本上就是我们公司增加的。换了一家公司后,这种现象有过之而无不及,几乎凡是需要连接单词的地方,都是用下划线。

作为一个中老年码农,我应该高兴,这说明码农已经开始占领世界了。

那么,纠结用下划线还是减号,是不是像纠结生僻的多音字,或茴字有几种写法,变得不合时宜?我是否应该随大流?

但据我有限的观察,在英语的技术世界里,仍然是有区分地使用两者,并没有无脑用下划线。

另外一点坚持就是逻辑上我们需要这两种符号:一种表示强连接,一种表示弱连接(如前所述)。两者并不完全是替代关系。

结语及倡议

下划线和减号都可用于连接字符串,这时它们的本质差别在于:分词逻辑的不同。

在国内软件领域,个人观察,下划线有被滥用的迹象。但在英文世界里,在代码以外,基本仍然遵循英文书写的习惯,使用减号作为连接符。

所以我倡议:如非不得已,尽量使用减号作为连接符。

概括地说,目标是给机器(比如编译器)看的领域,比如源代码和某些语言的文件名,使用下划线;目标是给人看的领域,比如UI,技术文章,遵循英文书写习惯,使用减号。这样具有最好的兼容性。

计算公式里出现的下划线什么意思(浅说下划线与减号)(5)

使用减号的连接

作为个人,入乡随俗,在某个特定的技术领域、特定的团体,以局部的规则和约定为优先。但另一方面,作为规范的制定者,要考虑“真正的主流”及其内在逻辑,不要轻易将规则扩大化。

,