一直都有系统学习正则表达式的想法,但由于缺乏耐心,每次都是刚开始就停止。最近去书店逛了逛,淘到一本非常专业的书,正好公司项目也不紧,就买一本回来研究,出乎意料的是,这本书写得太经典了,以至于我竟然不到一周就看完了,当然收获也不小,不过,由于正则表达式可读性是比较差的,这也是很多人觉得它难的原因之一,所以本书错误非常之多,但丝毫不影响我阅读。为了能让这本书的后续版本出现尽可能少的错误,我把发现的错误全部列出来供大家参考,这个过程异常艰辛,我似乎体会到此书翻译者的那种想吐的感受。
以下是我阅读《精通正则表达式 第3版》发现的错误,共24页36处错误,希望能对此书的爱好者有所帮助:(说明:错误的地方我用红色标注,建议修改的地方用蓝色标注(字体颜色这里可能无法显示),正则表达方式两端的符号我没有找到合适的对应,所以我用┌和 ┘来代替,同一页发现的错误个数默认是1,超过1个我会特别说明,每一页里面文字所在的行数从最上面页码下边的长横线起开始数,无关紧要的地方我用…表示,另外,由于我是做Java开发的,所以只阅读了1-6,8章节,其他7,9,10章未阅读,所以只列出了阅读部分所发现的问题。我已经给本书翻译余晟老师发过邮件,希望能够引起重视。)
1. 14页
第12行:
原文 置,然后匹配┌^From┘、┌Subject ┘或┌Date┘中的任意一个…
建议 置,然后匹配┌From┘、┌Subject ┘或┌Date┘中的任意一个…
错误原因:这里三个表达式是原表达式的分支,所以^不应该加在某一个分支前面。
2. 37页
第13行:
原文 print “celsuius C is … #返回摄氏和华氏温度
建议 print “celsuius C is … #输出摄氏和华氏温度
错误原因:这句代码的执行结果是在控制台上输入文本,而并不是返回。
3. 56页
倒数第02行:
原文 综合起来,我们得到:┌^From: (/s+) /(([^()]*)/)┘
建议 综合起来,我们得到:┌^From: (/S+) /(([^()]*)/)┘
错误原因:根据上下文理解,这里是大写S。
4. 93页
第12行:
原文┌(July|Jul)┘和┌/(July/|Jul/)┘能够取得同样的匹配结果…
建议┌(July|Jul)┘和┌(Jul|July)┘能够取得同样的匹配结果…
错误原因:这里说的是两个顺序相反的表达式。
5. 119页(2处错误)
第02行:
原文 范围内的所有字符…(例如,[0-9]与[908176354]是一样的。)…
建议 范围内的所有字符…(例如,[0-9]与[9081763542]是一样的。)…
错误原因:这里明显少了一个数字2,所以两个表达式不等价。
倒数第06行:
原文 出现NULL(而且可以用点号来匹配)。
建议 出现NUL(而且可以用点号来匹配)。
错误原因:这里是NUL字符而非NULL。
6. 189页
倒数第09行:
原文 在我们也把能把匹配三位数的多选分支放在最前面,这样…
建议 在我们就能把匹配三位数的多选分支放在最前面,这样…
错误原因:录入错误。
7. 193页
第06行:
原文 算式中的括号。我们…想到┌/bfoo/([^])*/)┘,但这行不通。
建议 算式中的括号。我们…想到┌/bfoo/([^)]*/)┘,但这行不通。
错误原因:红色部分的括号很明显是在字符组内部,这里可能是由于word的自动纠错的功能,在输入([^)]后,它会自动更换为([^]),但是这里本应该是([^)],所以要录入文字时需要把word此功能取消。
8. 194页
第5行:
原文 ┌/[^()]*(/([^()]*/)[^()]*)*/)┘
建议 ┌/([^()]*(/([^()]*/)[^()]*)*/)┘
错误原因:这里意为匹配嵌套的括号,所以最前面转义符/后面应该是被匹配文本的第一个(,另外粗体蓝色部分的)与前面一个粗体(配对,所以也应该是粗体。
9. 228页
倒数第03行:
原文 擎从最后保存的状态开始回溯,在“…anise”处开始尝试...
建议 擎从最后保存的状态开始回溯,在“…anese”处开始尝试...
错误原因:这里的anise应该是前面提到的文本中Japanese的后5个字母,所以是anese。
10. 262页
倒数第12行:
原文 的做法。举例来说,如果目标…,那么使用的自表达式就是…
建议 的做法。举例来说,如果目标…,那么使用的正则表达式就是…
错误原因:录入错误。
11. 265页(4处错误,此页错误最严重!!!)
第12行:
原文 是┌(/{[^}]*/)| +)*┘(它永远不会终止)。或许…
建议 是┌(/{[^}]*/}| +)*┘(它永远不会终止)。或许…
错误原因:这里的}是与前面的{配对,所以不应该是)。
第13行(中间部分表格第1行): 原文 Special normal 建议 special normal 错误原因:大小写错误,这里应该是小写字母开头,和后面的normal保持统一。 第14行((中间部分表格第2行)): 原文 ┌ +┘ ┌/{[^]}*/}} 建议 ┌ +┘ ┌/{[^}]*/}┘ 错误原因:字符组内部应该是^},所以^后面紧跟着的是}然后是];另外,本书宗旨正则表达式结尾符是┘,不是}。 第15行: 原文 使用我们学会的…,我们得到┌/{[^]}*/)┘* 建议 使用我们学会的…,我们得到┌/{[^}]*/)* 错误原因:字符组内部应该是^},所以^后面紧跟着的是}然后是];另外,此句的正则表达式还没有完,所以结尾不应该有┘。
12. 266页(2处错误)
第03行:
原文 ┌ *(/{[^]}*/} *)*┘
建议 ┌ *(/{[^}]*/} *)*┘
错误原因:猜想同7一样,也是word自动纠错的功能引起的。
倒数第02行:
原文 然后开始…的新一轮匹配。每次[^//"]+的匹配终止…
建议 然后开始…的新一轮匹配。每次┌[^//"]+┘的匹配终止…
错误原因:根据本书的宗旨,正则表达式应以┌┘包括起来。
13. 271页
倒数第03行:
原文 现在处理$field...
建议 #现在处理$field...
错误原因:这里是注释,应该以#开头。
14. 273页 第02行: 原文 你可能觉得…难以阅读,即使本书的体例已经尽量做到… 建议 你可能觉得…难以阅读,即使本书的示例已经尽量做到… 错误原因:录入错误。 15. 365页 正文第05行: 原文 sjava.util.regex一经发布就给人留下了深刻印象。它的功能… 建议 java.util.regex一经发布就给人留下了深刻印象。它的功能… 错误原因:单词拼写错误。
16. 367页
倒数第07行:
原文 /0octal要求开头为0,后接1到3位十进制数字。
建议 /0octal要求开头为0,后接1到3位八进制数字。
错误原因:octal是八进制的意思。
17. 368页(3处错误)
表8-3 错误1: 原文 表8-3:java.util.regex 中Match和Regex的方法 建议 表8-3:java.util.regex 中Pattern的公有属性 错误原因:可能是原作者的错误,这张表所列举的是公有(public)属性而非方法。 表8-3 错误2: 原文 Patern.UNIX_LINES… 建议 Pattern.UNIX_LINES… 错误原因:这里的类名很明显应该是Pattern。 表8-3 错误3: 原文 Pattern.CANNON_EQ 建议 Pattern.CANON_EQ 错误原因:java的Pattern类中只有CANON_EQ属性,没有CANNON_EQ属性。
18. 371页(2处错误)
第16行: 原文 IllegalAgumentException。 建议 IllegalArgumentException。 错误原因:单词拼写错误,而且java中的确只有IllegalArgumentException类。 倒数第04行: 原文 结果是‘matched [1st] from 12 to 15.’。在本章的所有例子… 建议 结果是‘matched [1st] from 11 to 14.’。在本章的所有例子… 错误原因:这里应该是原作者的错误,这里的运行结果是11-14,并不是12-15,而且从理论角度,字符串起始位置索引值是0,然后是1,2,3,...。猜想原作者运行此程序时离实际编写此章内容的时间有差异,所以在编写本章的时候并没有再运行此程序,根据记忆,所以才发生错误。 19. 373页 第01行: 原文 调用Patern.compile可能抛出两种类型的异常:如果… 建议 调用Pattern.compile可能抛出两种类型的异常:如果… 错误原因:单词拼写错误,而且事实上也是Pattern。 20. 374页 第13行: 原文 …和hasTran-sparentBounds方法来修改和查询… 建议 …和hasTransparentBounds方法来修改和查询… 错误原因:录入错误,此句在一行,不需要-连接符。
21. 377页(4处错误)
第09行: 原文 String gropu(int num) 建议 String group(int num) 错误原因:单词拼写错误。 倒数第06行: 原文 次方法返回整个匹配的终点的绝对偏移值,end… 建议 此方法返回整个匹配的终点的绝对偏移值,end… 错误原因:录入错误。 倒数第05行: 原文 MatcheResult toMatchResult() 建议 MatchResult toMatchResult() 错误原因:单词拼写错误。 倒数第02行: 原文 如果前一次匹配不成功,或者…调用 toMatcheResult 建议 如果前一次匹配不成功,或者…调用 toMatchResult 错误原因:单词拼写错误。
22. 378页(2处错误)
第05行: 原文 String regex = "(?x) ^(https?):// ([^/:]+) (?:(// d+))?"; 建议 String regex = "(?x) ^(https?):// ([^/:]+) (:?(// d+))?"; 错误原因:原文的?:是正则表达式中非捕捉型括号的标志,但这里并需要使用非捕捉型括号,而这里是用来匹配URL中主机名后面的端口号,如:8080,所以应该用:?,表示主机名后面可能会出现端口号,而端口号是以:跟在主机名后面的形式出现,所以应该用:?。 倒数第03行: 原文 string.replaceAll(regex,replacement) 建议 String.replaceAll(regex,replacement) 错误原因:String是Java的类名,所以首字母S应该大写,实际情况也是这样。
23. 401页
倒数第06行: 原文 有不断创建-回收 Mather 建议 有不断创建-回收 Matcher 错误原因:单词拼写错误。
24. 403页
倒数第06行: 原文 Java 1.5.0中 Character类的 isSomeing方法支持… 建议 无建议 错误原因:我查过Java API,没有找到Character类中的isSomeing方法,而且名字类似的方法也没有,所以不知道此处的真实用意:)。