Archive of

利用正则表达式精准匹配 Markdown 中的 Tag

在 Markdown 文档中,我们经常会使用 # 来标记标签(tag)。例如,#todo#feature 都可以作为标记嵌入文本中。然而,在 Markdown 中还存在另一种情况:代码块。代码块通常由单个或连续三个反引号(```)包裹,并且代码块内部可能会出现类似 #ff0000 这样的颜色值。如果不加以区分,就会把这些颜色值也识别为标签。

此外,为了避免误判,转义的反引号(\`)也不应被当作真正的分界符。为此,我们需要设计一个既能排除转义反引号,又能将连续的三个反引号作为一个整体处理的正则表达式。

挑战与需求

  • 处理代码块边界:Markdown 支持用单个反引号表示行内代码、用三个反引号表示多行代码块。正则表达式需要区分这两种情况,确保在代码块中的 # 不会被误认为标签前缀。
  • 转义字符的处理:例如 \` 这样的转义反引号不应计入反引号的配对判断中。
  • Tag 匹配规则:标签由 # 开头,后跟 1 至 32 个 Unicode 字母、数字或下划线,且必须在正确的边界下出现。

正则表达式解决方案

经过多次改进,我们最终得到了下面这个正则表达式:

(?=(?:(?:[^`]|\\`)*(?<!\\)(?<delim>```|`)(?:[^`]|\\`)*(?<!\\)(\k<delim>))*(?:[^`]|\\`)*$)(?<=(?:^|[^\\])#)[\p{L}_\p{N}]{1,32}(?=[^\p{L}\p{N}_]|$)

让我们逐步解析这条表达式的关键部分:

1. 保证反引号成对出现

表达式的开头部分使用了复杂的正向前瞻:

(?=(?:(?:[^`]|\\`)*(?<!\\)(?<delim>```|`)(?:[^`]|\\`)*(?<!\\)(\k<delim>))*(?:[^`]|\\`)*$)
  • 核心思想:通过匹配一系列非反引号或转义反引号的字符,再加上捕获组 (?<delim>```|)`,我们捕获了第一次出现的“分界符”——它可能是单个反引号,也可能是连续三个反引号。
  • 反向引用:利用 \k<delim>,确保后续匹配的分界符与前面捕获到的完全一致。这样,无论遇到的是行内代码还是代码块,都只视作一个整体。
  • 成对匹配:整个正向前瞻确保了目标区域内所有未转义的反引号都是成对出现的,避免了误将代码块内部的内容当作标签判断依据。

2. 确保标签前缀正确

接下来的部分:

(?<=(?:^|[^\\])#)
  • 作用:这个正向后查断言确保了标签必须由一个 # 开头,而这个 # 不能被反斜杠转义(即不应为 \#)。

3. 匹配 Tag 内容

标签的主体部分由下面这段完成:

[\p{L}_\p{N}]{1,32}(?=[^\p{L}\p{N}_]|$)
  • 匹配范围:这里 [\\p{L}_\\p{N}] 表示 Unicode 字母、数字以及下划线。{1,32} 限定了标签的长度为 1 至 32 个字符。
  • 边界条件:紧跟的正向查找断言 (?=[^\p{L}\p{N}_]|$) 确保标签后面紧跟的是非单词字符或已经到达字符串末尾,防止匹配到类似 #todoing 这种不完整的标签。

小结

这条正则表达式综合了多种复杂情况,既能处理 Markdown 中单反引号和三反引号的代码块,又能排除转义反引号的干扰,同时严格匹配标签格式。对于开发者来说,这样的表达式在解析 Markdown 文档、提取标签或进行格式化处理时非常有用。

当然,正则表达式的可读性和维护性是一个平衡点。虽然这条表达式在处理边界情况时表现出色,但在实际应用中可能还需要根据具体场景做出微调。希望这篇文章能为你在 Markdown 文档解析方面提供一些灵感和帮助。

网友语录 - 第19期 - 生活,一半是回忆,一半是继续

这里记录我的一周分享,通常在周六发布。


“嗯,我有几棵枯树需要伐掉……车库里都有些什么工具呢?两个榔头、一些钉子,几把铁锹,还有一把手锯。啊,太好了,有把手锯。”

环境影响人的思维,车库里没有电锯,这个人就想不到借一把电锯来干活。然而,合适工具的生产力是蹩脚工具几十倍。

在挽起袖子大干一场之前,思量一下手头的“最近便的工具”,也是“最适合的工具”吗?还是只是“凑和将就”着用?“凑和将就”其实是在欠债,而欠下的债总是要还的。 -- 书摘《你就是极客》

…more

书摘:个人电脑诞生前计算机世界的样子以及人们如何使用计算机

下面三条长书摘摘自一本2001年出版的老书《Harley Hahn's Internet Advisor》的中文版,以下内容摘自这本书的第8章,很生动了介绍个人电脑诞生前计算机的样子以及那时的人们如何使用计算机。我一直热衷了解这类旧事,就摘抄下来分享给大家,希望你会喜欢。当然啦,如果你不感兴趣,看到这里就可以关掉了。谢谢!

使用计算机曾经是一项社交活动

我们的讨论将从“古老的”20世纪60年代开始,在那个时候,没有因特网、没有电子邮件、也没有个人电脑。在那个时期,计算机这个词还指的是玻璃机房里的那些既庞大又昂贵、还特别娇气的东西,而人们则以一种敬畏的态度来对待它们。

在我还是个毛头小伙子的时候,“计算机”这个词指的是那些人们现在称为“巨型机”之类的东西。这些机器非常贵重,能买得起它们的组织只有大公司、大学和政府。这些计算机有许多部件,还净是一些巨大的金属盒子,安放这些大盒子的房间对温度和湿度都有严格的要求。 这些老式计算机大都是由IBM公司制造的,而且基本上都是以出租而不是销售的形式交付给使用方(IBM公司在那个时期拥有绝对的垄断地位)。当时最先进的计算机非IBM System/360系列莫属。因为这些机器太昂贵了,所以必须有很多人共享它才合算,而共享的人数往往会有几百甚至几千人。

当时的计算机到底有多贵呢?当我还在念大学的时候,1兆字节的内存就价值 100万美元,而且体积会有好几个冰箱那样大(当时的100万美元可比现在值钱)。不过,那时还很少有内存超过1兆字节的计算机。

这么昂贵的计算机当然要摆在一间大屋子里。这些屋子往往有很多窗户,目的是为了让路过的人——特别是来访者—能够看到屋子里的计算机并受点“刺激”。这类房间通常被称为“计算机机房”。

在当时,通常只有操作员能够获准进人机房并直接使用计算机。大多数巨型 机都要求随时有一个以上的操作员在场才能顺利地运转。 既然普通人不能进人机房并直接使用那台机器,他们又是怎样来使用计算机的呢?在那时,程序都是打在穿孔卡片上的,每张卡片上有一条语句—也就是说,一个500行的程序就需要500张卡片,人们必须把这些卡片读到计算机里去。

要想编写程序,就得使用一台名为“穿孔机”的机器。这种机器的外观和 1940年拍的科幻电影里一件来自所谓“未来”的道具差不多,就像是一堆莫名其妙的铁齿上放着个打字机。你得先把空白卡片放到这台机器里,然后用打字机每次一行地敲人自己的程序。每敲入一个字符,穿孔机就会在卡片上打一组洞。每个字符都是用特定的洞眼组合来代表的。

打完所有的卡片之后,就可以去运行程序了。得把那些卡片拿到一台名为“读卡机”的机器那儿去。把你的那些卡片交给操作员,再由他们把那些卡片放到读卡机里。卡片很快就会读完,每次只能读一张卡片。当卡片经过读卡机时,上面的洞眼将被检测出来,而卡片上的数据就会被读到计算机的一个临时存储区域里去。所有卡片都读完后,你的程序就会被放到一个内部队列里等着轮到它。终于,轮到计算机来执行你的程序了。在许多系统上,你可能要等很长时间才能轮到计算机去执行你的程序。我有一位当时在UCLA(加州大学洛杉矶分校)工作的朋友,他告诉我,为了运行他的程序,他曾经等过一整天。

当时,惟一的输出形式是打印在纸上。一旦轮到你的程序开始运行,它的输出就会源源不断地被打印到长长的打印纸上。另外一个专门负责打印机的操作员会把这些纸整理好,把不同程序的输出分开。要想查看自己程序的运行结果,你就得到打印机房自己找去。它们往往会有一大卷,十几页或者几十页长。找到你程序的输出结果后,得把它们拿到另外一个有桌子的房间里去,然后把打印纸铺 在桌子上仔细地进行检查。如果出了错,你就得回到穿孔机那里重新打孔一张卡片,用它换掉原来的那一张,然后从头重复一遍上述的过程。

我之所以不厌其烦地讲述这些细节,是为了让大家明白编写和运行程序曾经是一种节奏缓慢而又消耗时间的活动。它同时也是一种社交活动。大家待在一起花费时间,人们会相帮着检查各自的程序、在穿孔机旁边或者在打印机房的外面聊会儿闲天。总之,在当时,使用计算机会让你觉得自己是某个集体中的一员。

那时候的乐趣可真多。


计算活动的黄金时代

随着技术的进步,计算技术也有了长足的发展,同时也改变了刚才介绍的那种社交环境。读卡机和打印机被终端取而代之,这类设备使人们能够从远程地点使用计算机。

每台终端都有一个键盘和一个显示设备,并且连接到一台计算机上。人们通过终端来编写和运行程序:在键盘上打字,在显示设备上查看程序的输出。

早期终端的输出是打印在一大卷纸上的。当时最常见的终端是IBM 2740和IBM 2741,它们的外观与老式的Selectric打字机差不多(这种打印机的按键是些小圆疙瘩)。几年之后,CRT终端问世了,程序的输出显示在一个内建的屏幕上,显示屏和电视的样子差不多(CRT的意思是cathode ray tube, 阴极射线管)。 与穿孔机、读卡机和笨重而又昂贵的打印机相比,这两种终端纸质输出和屏幕输出都是一种巨大的进步。用不着给卡片打孔、用不着把它们放到盒子里、也用不着把它们拿到读卡机那儿去,人们只要坐在一台终端的前面就可以编写和运行程序了。

没过多久,原来满屋子的穿孔机换成了满屋子的终端。虽然使用计算机已经稍微有了点与世隔绝的味道,但仍给人们保留下一种属于某个团体的感觉。人们聚在终端室里工作和交谈,友好和互相帮助的传统依然很强烈。在那个时期,要是你想结识些聪明人,最好的办法就是泡在终端室里;在那儿可以结交到多少好朋友啊。

当时的计算机依然很昂贵,所以没人有自己的机器。于是,人们开发出 了一种被称为“分时系统”(time-sharing system)的技术,这种技术可以让很多 人同时使用同一台计算机。在一个分时系统上,一台计算机会连接着许多台终端,而操作系统使计算机运转起来的主控程序则被设计成能够在不同任务之间进行快速切换的形式。这样,一台计算机就可以支持几十名、甚至几百名用户同时上机,而程序都运行在后台。

到了20世纪70年代的初期,AT&T(美国电话电报公司)旗下的研究机构贝尔实验室(Bell Lab)开发出了一种称为UNIX的分时系统。UNIX是个不同寻常的操作系统,它是由一些极其聪明的人为另外一些极其聪明的人而开发的。没过多久,UNIX就一跃成世界上最流行的分时系统,在许多大学和研究机构里得到了推广。

从一开始,UNIX操作系统就是为拥抱通信和共享而设计的。这与其他早期操作系统—当时的操作系统大都是由计算机制造商开发—的做法截然不同。例如,负责开发IBM操作系统的程序员们想当然地认为人们宁愿把自己拥有的信息隐藏起来也不愿意与别人交流,所以根本没有在IBM操作系统里为人们提供用来进行通信和交流的手段。又因为IBM垄断着与它们的计算机有关的一切事物,所以IBM公司以外的人根本不可能对该操作系统做任何大的改动。

但负责开发UNIX的程序员们却没有这样想。开发UNIX的程序员们大都工作在一个共享工具和互相帮助蔚然成风的环境里,所以他们开发出来的UNIX也鼓励人们与其他人共享自己的程序和数据。

此外,任何一位UNIX用户都能随时查看到这个操作系统各种组件的实际程序(源代码)。这就意味着任何人都可以对它作出修改和改进,然后再把这些改进与其他UNIX用户分享。这种做法的好处是,一旦某位程序员已经解决了某个问题,其他程序员就没必要再浪费时间去重复解决同-个问题了。它鼓励UNIX用户团结合作,把他们的工具弄得越来越好,而这正是UNIX得以迅速推广和流行的原因之一。

UNIX得以迅速推广和流行的另一个理由是这种操作系统很有趣。例如,每个UNIX系统都内建了一些游戏。UNIX用户在“享受”这些游戏—一因而也更喜欢它——的同时,还能学到这些游戏的工作原理,进而开发出更多的游戏。

但UNIX得以迅速推广和流行的最重要的原因是它鼓励人们进行通信和交流。早在20世纪70年代的初期,UNIX用户就已经能通过终端来发送电子邮件和进行交谈了。此外,每个UNIX系统都能与其他UNIX系统连接起来。在因特网出现之前很久的时候,美国和欧洲等地的许多计算机就已经通过一种特殊的基于UNIX操作系统的网络协议即UUCP协议彼此连接在了一起。与现今的因特网相比,UUCP不仅速度慢,用起来也不很方便,但它却为信息和数据的自由流动作出了很大的贡献。很快地,全世界的学术和科研机构就都在使用着UNIX操作系统来发送电子邮件、共享文件和开展协作了。 每个UNIX系统都有一个内建的在线帮助手册,人们完全可以通过对它的自学而掌握各种基本操作。不过,UNIX的精妙之处包括它的高级使用技巧和程序设计技术如果没有个人之间非正规方式的传授,单靠书本是很难掌握的。在计算机的发展历史上曾经有过这样一个时期,那时候,计算机的使用方法和程序的编写方法都是通过人们个人之间的交往来传授的。如果你只用过PC或者Macintosh,那肯定很难相信这一点,可这的确是个事实。就拿UNIX来说吧,虽然已经出版了很多介绍UNIX操作系统的教科书(我就写过好几本),但UNIX的精髓主要还是通过人们个人之间的交往才得以流传下来的。而这种学习方式与其说是一种智力活动,还不如说是种社交活动更当。

可以这么说,在20世纪70年代的中期,也就是因特网开始流行的20年前,世界各地的聪明人使用的都是UNIX,这是一种鼓励人们与其他聪明人进行交流、协作和共享的计算机系统。这些人里面大部分是研究人员和学生。他们使用着计算机,他们喜欢使用计算机。在计算机的帮助下,他们解决了许多富于挑战性的问题。 在本书的一开始,我就提出了“黄金时代”的概念,它指的是这样一种历史时期:某项技术还是新生事物,使用这些技术的人还都很“天真无邪”,并且会有一个短暂但辉煌的创新喷涌期。我还谈到曾经有过的因特网黄金时代是如何逝去的。远在因特网黄金时代之前,曾经有过 个“计算的黄金时代”。它以UNIX家族为核心,涌现了数量惊人的发明和发现,并对此后的程序设计文化产生了深远的影响。

在这个时期,许多计算机用户享受到拥有大量个人之间亲密“接触”的快乐。这是历史上第一个也是最后一个人们在计算机上花费了大量时间依然能够满足他们与别人进行个人交流的基本生理需要的时期。那时候,从大的方面来说,使用计算机还是一种社交活动,不像现在这样几乎完全成为一种与世隔绝的活动。

可惜的是,这个计算的黄金时期持续了还不到10年。令它走向衰亡的种子是在80年代刚开始时播下的,当时,一项新技术令人意想不到地出现在人们眼前。在很短的时间里,计算领域就沉迷于这项新技术而不能自拔,我们的文化也因为这项新技术而发生了不可逆转的变化。 这项新技术给世界各地的人们带来了20世纪70年代的程序员们所梦想的计算能力,从这个意义上讲,它是一种福音。可这项新技术同时也割断了计算机用户之间的亲密“接触”,催生出一种与世隔绝的失落感,这种感觉持续至今仍挥之不去。

像所有的革命一样,这项新技术也是悄悄来临的。在1980年9月6日,当全世界的大多数程序员和计算机用户还被牢牢圈在70年代的技术藩篱之中时,IBM公司的三个人开了一个会。在会上,一个研发小组的负责人向两位IBM执行官展示了一个小盒子。两位执行官看过之后觉得很不错,于是就作出了一个永远改变了世界的决定。


个人电脑诞生记

在20世纪70年代结束的时候,占据主导地位的计算机仍然是IBM公司生产的巨型机。但一种名为“小型机”的计算机已经被人们开发出来并得到了广泛的应用。事实上,我在上节提到的UNIX操作系统就是运行在小型机上的。虽然名字里有个“小”字,可(按今天的标准看)依然相当巨大、昂贵、难以维护。这个“小”是相对于巨型机而言的。

到了1980年,有儿家公司开始研制微型计算机,这些更小的机器比较适合个人使用。当时最流行的两种微型计算机分别是苹果电脑公司生产的Apple II和Radio Shack公司生产的Tandy TRS-80。购买这类机器的人主要是电脑爱好者,老百姓大多不感兴趣。

此时IBM也推出了几种小计算机,其中包括System /23 Datamaster(商用),Displaywriter(一台独立的文字处理机)以及IBM 5100和5110(程序员用)。这些机器的销售并不理想,IBM也认它们是食之无味,弃之可错的鸡肋。

可IBM公司里的某些人还是很看好这方面的新技术,并且着手研究为商业市场开发一种全新微型计算机的可行性。但公司上下对这种投人普遍持反对意见,毕竟能挣大钱的还是 巨型机和小型机。即使人们把那些功能不足以运行IBM标准商业软件的小计算机买回去,又能派上什么用场呢?

在1980年5月,1BM公司董事会主席Frank Cary和总裁John Opel这两位高层执行官认真研究了这个问题,他们得出的结论是:一台这样的计算机有可能成为IBM公司整个产品线的一个虽然微不足道但很有价值的补充。他们决定成立一个由8名工程师和5名市场分析人员组成的研发队伍来研究这件事。

这个后来被称为“13人小组”的研发小组于1980年7月开始工作。到了1980年的9月6日,“13人小组”的负责人Bill Lowe面见Crayi 和Opel并展示了一个工作模型。它还没有正式的操作系统,而且使用的是与System /23完全一样的处理器芯片。不知什么原因,Cray和OpeI都很喜欢他们看到的东西,很快就批准了设计一种全新的机器IBM个人电脑的项目。他们可能是这样想的:如果这种机器确实效果不错,大概能卖它儿万台。可在1980年,这个数字对IBM来说不过是块小土豆。

IBM公司于1981年8月12日正式发布了这种个人电脑。几年之内,这种人称IBM PC的小计算机彻底改变了计算机工业的格局。小企业第一次有机会拥有自己的计算机。到了80年代的中期,个人电脑此时,生产它的厂家已经不止IBM一家了已经在商业领域得到了广泛的使用。到了90年代,它们在普通家庭里也很常见了。

毫无疑问,个人电脑对世界经济作出了巨大的贡献。但是,这种新型、低廉、无处不在的计算机所带来的巨大的经济增长也是有代价的。这个代价就是人们在社会交往方面日渐孤立。

书摘:《女士品茶》里的几个故事

《女士品茶》

冈贝尔的故事

冈贝尔的一生富有传奇性。在20世纪20年代末至30年代初,他是德国一所大学里资历尚浅的一名教师。从他早期发表的论文中看得出来,他是个极具潜能的人,只是当时还没有机会得到一个令人尊敬的地位罢了。同样,他当时的职位也远算不上稳固,是否有能力养家糊口,还取决于政府那些权威的随心所欲。当时,纳粹在德国境内已经渐趋猖獗,国家社会主义工人党虽然是正式的正常组织,实质上却是由一群歹徒纠集而成的。俗称“褐衫队”(Brown Shirts)的纳粹冲锋队是一个专门从事恐吓与胁迫、恣意暴力和谋杀来执行纳粹党意志的暴徒组织。任何批评纳粹党的人都会遭到暴力攻击,而且通常就发生在城市的大街上,以杀一儆百。

冈贝尔有个朋友就是这样在光天化日之下遭到攻击并被公然杀害的。照理说,会有许多目击证人可以指认凶手,但法院往往宣称罪证不足而使纳粹突击队逍遥法外。

冈贝尔曾参加过一场审判,他亲眼目睹了法官全然无视任何证据,恣意裁决,纳粹党徒则在法庭上肆无忌惮地狂呼。

对此,冈贝尔惊骇万分。于是,他开始着手调查那些凶手公然行凶的其他案例,结果没有一例被判有罪。最终他得出结论:司法部门已经被纳粹党人所控制,很多法官要么是纳粹的支持者,要么干脆就是纳粹所雇佣的。

冈贝尔搜集了许多案例,走访证人,证明判决那些凶手无罪是错误的。1922年,他出版了《四年的政治谋杀》(Four Years of Political Murder)一书,把他搜集调查的结果公之于众。由于发现很多书商根本不敢销售他的书,他不得不亲自去为自己的书安排发行分销。与此同时,他还在继续搜集案例,并于1928年又出版了《政治谋杀的原因》(Causes of Political Murder)一书。

此外,他还设法成立一个反纳粹的政治团体,但是他的多数学术界同事太害怕了,甚至那些犹太籍的朋友们都吓得不敢参加。1933年纳粹党取得了政权,当时冈贝尔正在瑞士参加一个数学会议。他本打算立即赶回德国去与这个新政权做斗争,但朋友们极力劝阻了他,因为只要他一越过边境,就会立刻遭到逮捕,并被处决。在纳粹掌权的最初阶段,在这个新政府还没来得及控制所有的出入境事务之时,少数犹太籍教授,如德国的顶尖的概率论大师里夏德・冯・米泽斯(Richard von Mises),他们已经预料到即将发生的灭顶之灾,提前逃离了德国。冈贝尔的朋友也趁这段有利的混乱时机,带着他的家人离开了德国。他们跑到法国 暂避一时,但是,1940年纳粹又入侵了法国。

冈贝尔与家人继续逃往尚未沦陷的法国南部。当时统治法国的是纳粹扶植的傀儡政府,对德国惟命是从。像冈贝尔这样的德国民主党人已经是危在旦夕,因为他们都被列入了叛国者的黑名单,纳粹要求法国政府将这些人移交过去。除了冈贝尔,滞留在法国马赛的德国逃亡者还有德国作家托马斯・曼(Thomas Mann)的哥哥海因里希・曼(Heinrich Mann)、犹太裔小说家利翁・福伊希特万格(Lion Feuchtwanger)。当时驻马塞的美国领事海勒姆・宾厄姆四世(Hiram Bingham IV)违反美国国务院的规定,擅自给这批德国流亡者发了签证。

宾厄姆为此受到华盛顿的谴责,最终由于此举而丢掉了他在马赛的职位,但宾厄姆毕竟尽他所能拯救了很多人,这些人如果留在纳粹统计下,将必死无疑。冈贝尔与家人到了美国之后,在哥伦比亚大学谋到一个职位。

虽然读者对此可能不太相信,但在数学研究领域,一个人写文章的风格确实发挥着很重要的作用。有些数学文献的作者似乎写不出让人容易理解的文章;有些人则似乎以写成一行又一行的数学符号与注释为乐事,一篇论文中充斥着无比繁琐的细节,以至于把总的思考都迷失在了微不足道的细节中。与之相反,有些作者却总是有能力用非常简单而有说服力的方式表达复杂的思想,数学的发展在他们的表达中显得如此的鲜明而平实。只有在回顾已经学到些什么时,读者才会确实认识到结果的伟大力量。奈曼就是这样的作者,读他的论文是件令人愉快的事,数学观点自然地展开,使用的符号简单得令人无法相信,结论的显现竟如此的自然,以至于让人感到难以理解,不禁要问,为什么很久以来居然没有人发现这项结论?


奈曼的故事

就在希特勒入侵波兰,将邪恶之幕笼罩欧洲大陆之前,奈曼就到了美国,并在加州大学的伯克利分校开始创建统计系。在那里他一直工作到1981年去世,这期间,他把该系创建成全世界最重要的学术性统计学系之一。他把一些统计学界赫赫有名的人物引入该系,同时也提拔了一些默默无闻的人,这些人正致力取得卓越的成就。例如,大卫・布莱克韦尔(David Blackwell)原来只是只身孤单地在霍华德大学(Howard University)工作,没有数理统计同行与他来往。由于他的种族原因,他一直没能在“白人”学校谋得一职,尽管他很有潜能。奈曼把他请到了伯克利。此外,奈曼还招了一位出身法国农民家庭的研究生吕西安・勒卡姆(Lucien Lecam),他后来成为世界领先的概率学家。

奈曼总是非常和善地对待他的学生和同事。他们常常津津乐道的是系里每天下午茶歇的欢乐时光,这是由奈曼主持的他与职员亲近接触的一个重要场合。他总是亲切地鼓励学生和同事谈谈自己最新的研究成果,同时很和蔼地提出他自己的思路和见解,给出评论,加入大家的讨论。他常常在下午茶歇即将结束时举起茶杯说“为尊敬的女士们!”他特别关照女士,鼓励她们在学术生涯上不断进步。在他的女弟子当中,伊丽莎白・斯科特(Elizabeth Scott)博士是较为杰出的,她与奈曼一起做研究,共同发表论文,范围从天文学到致癌物研究,甚至动物学。还有伊夫琳・菲克斯(Evelyn Fix)博士,她在流行病学的研究上有很重要的贡献。

直到费歇尔于1962年去世,奈曼一直受到这位天才的尖刻批评。奈曼每做一件事都会遭到费歇尔的批评。如果奈曼成功地证明出了费歇尔某项非常难解的叙述,费歇尔就说奈曼误解了他写的东西;要是奈曼扩充了费歇尔的某个观点,费歇尔就批评奈曼说他把好端端的理论用错了地方。对比,不论是付诸笔端,还是在私人场合,奈曼从不回应(如果我们相信奈曼同事的说法)。

在奈曼去世前的一次访谈中,奈曼说了一件发生在20世纪50年代的往事。当时他准备在一次国际研讨会上公开发开一篇用法语写的论文。当他步上讲台时,意识到费歇尔也坐在听众席上。在演讲论文时,他知道一场激辩难免,于是开始武装自己,他预计费歇尔会抓住论文里某个无关紧要的小地方,将论文和他本人攻击得体无完肤。奈曼讲完之后,等待听众提问,结果只有几个问题。费歇尔相当平和,一言未发。后来奈曼才知道,费歇尔不会讲法语。


有关条件概率的故事

从8世纪的早期,威尼斯共和国是地中海一带的一个主要的强权国家。在其政权鼎盛时期,威尼斯控制了大部分的亚得里亚海岸,以及克里特岛和赛浦路斯岛,同时还垄断了东方通往欧洲的商业贸易路线。威尼斯共和国由一群贵族家族所统治,这些家族之间保持着某种民主的程序。整个国家名义上的领袖是总督,从公元697年该共和国成立起,到1797年被奥地利吞并,总共有150余任总督,有的任期很短,只有1年或不到1年,也有的任期长达34年。在位的总督去世之后,该共和国会遵守一项很复杂的选举程序,他们先从贵族家族的长者当中,以抽签的方式选出一小群元老,这些被选出的元老还会再挑选一些人加入到他们之中,之后再从这一扩大的元老群中以抽签方式选出一小群人。这样的程序进行几次之后,会选出一群最后的总督候选人,总督就在这群人当中产生。

在威尼斯共和国历史的早期,每阶段的抽签都要准备一批大小相同的蜡球,有的蜡球里什么都没有,有的蜡球里面却有一张小纸条,上面写着“元老”二字。到了17世纪,最后几个阶段用的道具是大小完全相同的金球与银球。公元1268年,当多杰・拉伊涅里・泽诺(Doge Rainieri Zeno)总督去世时,在第二阶段有30位元老,于是准备了30个蜡球,其中9个蜡球内藏有“元老”纸条。一个小孩被带过来,他从装有蜡球的篮子中取出一个蜡球,交给第一位元老候选人,这位元老候选人就打开蜡球,看看自己是否能够成为下一阶段的元老候选人。接着,小孩从篮子中取出第二个蜡球,交给第二位元老候选人,第二位再打开蜡球,以此类推。

在小孩选出第一个蜡球前,候选人群中的每个成员被选为下个阶段元老的概率是9/30。如果第一个蜡球是空的,剩下的候选人中每个人有9/29的概率成为下坠估摸元老。但如果第一个蜡球里有纸条,则其余人被选中的机会就剩下8/29。一旦第二个蜡球被选定且被打开,则下一个人被选中成为元老的概率同样会减少或增加,是减少还是增加取决于前次的抽球结果。这样继续抽下去,直到所有的9个纸条都被抽出为止。而在这时,剩下的候选人下一阶段成为元老的概率就降为零。

这是条件概率的一个例子。某一特定候选人被选为下一阶段元老的概率,取决于在他的选择之前被选出的蜡球。J・M・凯恩斯曾指出,所有的概率都是条件概率。用凯恩斯所举的一个例子:从他的图书室的书架上随机地选择一本书,而选中的书是精装本的概率,也是一种条件概率,其条件取决于他的图书室里究竟有多少书,以及他怎样“随机”地选取。

Tired of Git Branch Case Sensitivity? Here's a Fix for Git Bash Users

Hey fellow devs! Here’s a small but super useful Git trick for dealing with that annoying branch case sensitivity issue. You know the drill—someone creates feature/UserAuth, but you type feature/userauth. On a case-sensitive OS, Git tells you the branch doesn’t exist. On a case-insensitive OS like Windows or macOS, it’s worse—you switch to the wrong branch without realizing it. Later, you discover both feature/userauth and feature/UserAuth exist on GitHub. Ouch.

This is particularly painful when working with Windows or macOS, where the filesystem is case-insensitive, but Git isn't. Add in a mix of developers with different habits (some love their CamelCase, others are all-lowercase fans), and you've got yourself a daily annoyance.

The Fix

I wrote a little Git alias that makes checkout case-insensitive. It's basically a smarter version of git checkout that you use as git co. Here's what it does:

$ git co feature/userauth
⚠️ Warning: "feature/userauth" is incorrect. Switching to: "feature/UserAuth"
Switched to branch 'feature/UserAuth'

Nice, right? No more "branch not found" errors just because you got the case wrong!

Important Note ⚠️

This works in:

  • Windows Git Bash (tested and used daily)
  • Should work in macOS/Linux (though I haven't tested it - let me know if you try!)

But it won't work in:

  • Windows CMD
  • Windows PowerShell
  • Any other Windows terminals

Why? Because it uses Bash commands and parameters. But hey, you're using Git Bash anyway, right? 😉

How to Install

Just run this in Git Bash:

git config --global alias.co '!f() {
  # If no args or help flag, show git checkout help
  if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    git checkout --help;
    return;
  fi;
  # If any flags are present (except -q or --quiet), pass through to regular checkout
  if [ $# -gt 1 ] || [[ "$1" == -* && "$1" != "-q" && "$1" != "--quiet" ]]; then
    git checkout "$@";
    return;
  fi;
  # Pass through if argument is a commit reference (HEAD, SHA, tag, etc)
  if [[ "$1" =~ ^HEAD([~^]|@{)[0-9]*$ ]] || # HEAD~1, HEAD^1, HEAD@{1}
     [[ "$1" =~ ^(FETCH_HEAD|ORIG_HEAD|MERGE_HEAD)$ ]] || # Special refs
     [[ -f ".git/refs/tags/$1" ]]; then # Tags
    git checkout "$@";
    return;
  fi;
  # Fetch and prune to ensure we have latest refs
  git fetch --prune --quiet;
  # Check both remote and local branches
  correct_branch=$(git branch -r | sed "s/^  origin\///" | grep -i "^$1$");
  if [ -z "$correct_branch" ]; then
    correct_branch=$(git branch | sed "s/^[* ] //" | grep -i "^$1$");
  fi;
  # If branch found with different case, warn and use correct case
  if [ -n "$correct_branch" ] && [ "$1" != "$correct_branch" ]; then
    echo "⚠️ Warning: \"$1\" is incorrect. Switching to: \"$correct_branch\"";
    git checkout "$correct_branch";
    return;
  fi;
  # Otherwise just pass through to regular checkout
  git checkout "$1";
}; f'

What's Cool About It?

  • Finds your branch regardless of how you type the case
  • Still works normally for everything else (files, creating branches, etc.)
  • Shows you the correct branch name when you get the case wrong
  • Auto-fetches to make sure it sees all remote branches

The best part? If it doesn't recognize what you're trying to do, it just passes everything to regular git checkout. So it won't break any of your normal Git workflows.

Real World Usage

I use this daily in a Windows-heavy dev team where we have branches like:

  • feature/UpdateUser
  • hotfix/FixLoginBug
  • release/v2.0.0

And now I can type them however I want. Life's too short to remember exact branch capitalization!

Give It a Try!

If you're using Git Bash on Windows and tired of case sensitivity issues, give this a shot. It's one of those small tools that just makes your day a tiny bit better.

And hey, if you try this on macOS or Linux, let me know how it goes! Always curious to hear if these tricks work in other environments.