一系列计算机相关图书列表

代办事项中一直存在这样一个列表,一直没有完全吸收,这里先列着慢慢消化吧。不过大多数情况下都是直接豆瓣搜索看评价看了,也没有来得及维护这个列表,找个时间整理成豆列吧。

计算机系统与网络

  • 《图灵的秘密》
  • 《计算机系统概论》
  • 《深入理解 Linux 内核》
  • 《深入 Linux 内核架构》
  • 《TCP/IP 详解 卷 1:协议》
  • 《Linux 系统编程(第 2 版)》
  • 《Linux 内核设计与实现(第 3 版)》
  • 《深入理解计算机系统(原书第 2 版)》
  • 《计算机程序的构造和解释(原书第 2 版)》
  • 《鸟哥的 Linux 私房菜(基础学习篇 第三版)》
  • 《编码:隐匿在计算机软硬件背后的语言》
  • 《性能之颠:洞悉系统、企业与云计算》
  • 《UNIX 网络编程 卷 1:套接字联网 API(第 3 版)》
  • 《UNIX 网络编程 卷 2:进程间通信》
  • 《Windows 核心编程(第 5 版)》
  • 《WireShark 网络分析就这么简单》
  • 《WireShark 网络分析的艺术》

编程通用

  • 《编程原本》
  • 《代码大全》
  • 《UNIX 编程艺术》
  • 《代码整洁之道》
  • 《编程珠玑(续)》
  • 《编程珠玑(第 2 版)》
  • 《软件调试的艺术》
  • 《修改代码的艺术》
  • 《编程语言实现模式》
  • 《编写可读代码的艺术》
  • 《程序设计方法(中文版)》
  • 《解析极限编程:拥抱变化》
  • 《精通正则表达式(第 3 版)》
  • 《现代编译原理 : C 语言描述》
  • 《编译原理 : 原理、技术与工具》
  • 《重构:改善既有代码的设计》
  • 《七周七语言:理解多种编程范型》
  • 《调试九法:软硬件错误的排查之道》
  • 《程序设计语言:实践之路(第 3 版)》
  • 《计算的本质:深入剖析程序和计算机》
  • 《设计模式 : 可复用面向对象软件的基础》

算法与数据结构

  • 《算法(英文版 第 4 版)》
  • 《算法导论(原书第 2 版)》
  • 《Python 算法教程(第 2 版)》
  • 《算法设计与分析基础(第 3 版)》
  • 《学习 JavaScript 数据结构与算法》
  • 《数据结构与算法分析 : C++ 描述(第 3 版)》
  • 《数据结构与算法分析 : C 语言描述(第 2 版)》
  • 《数据结构与算法分析 : Java 语言描述(第 2 版)》

职业修炼与规划

  • 《大教堂与集市》
  • 《卓有成效的程序员》
  • 《程序员的职业素养》
  • 《程序员修炼之道:从小工到专家》
  • 《软件开发者路线图:从学徒到高手》
  • 《我编程,我快乐:程序员职业规划之道》
  • 《程序员的思维修炼:开发认知潜能的九堂课》
  • 《高效程序员的 45 个习惯:敏捷开发修炼之道(修订版)》

大师访谈

  • 《编程大师智慧》
  • 《编程大师访谈录》
  • 《编程人生 : 15 位软件先驱访谈录》
  • 《奇思妙想 : 15 位计算机天才及其重大发现》
  • 《图灵和 ACM 图灵奖(1966-2015 第五版) 纪念计算机诞生 70 周年》

架构 / 性能

  • 《微服务设计》
  • 《大数据日知录》
  • 《企业应用架构模式》
  • 《Web 性能权威指南》
  • 《SRE:Google 运维解密》
  • 《发布!软件的设计与部署》
  • 《高扩展性网站的 50 条原则》
  • 《大型网站技术架构:核心原理与案例分析》
  • 《恰如其分的软件架构:风险驱动的设计方法》
  • 《软件系统架构:使用视点和视角与利益相关者合作(第 2 版)》

Web 前端

  • 《高性能 JavaScript》
  • 《锋利的 jQuery(第 2 版)》
  • 《编写可维护的 JavaScript》
  • 《你不知道的 JavaScript(上)》
  • 《JavaScript 权威指南(第 6 版)》
  • 《JavaScript 语言精粹(修订版)》
  • 《JavaScript DOM 编程艺术 (第 2 版)》
  • 《JavaScript 高级程序设计(第 3 版)》
  • 《JavaScript 异步编程:设计快速响应的网络应用》
  • 《Effective JavaScript:编写高质量 JavaScript 代码的 68 个有效方法》
  • 《HTML5 权威指南》
  • 《HTML5 秘籍(第 2 版)》
  • 《HTML5 与 CSS3 基础教程(第八版)》
  • 《CSS 揭秘》
  • 《CSS 设计指南(第 3 版)》
  • 《CSS 权威指南(第 3 版)》
  • 《深入浅出 HTML 与 CSS》

Java 开发

  • 《Java8 实战》
  • 《Java 并发编程实战》
  • 《Java 性能权威指南》
  • 《Java 程序员修炼之道》
  • 《实战 Java 高并发程序设计》
  • 《Java 编程思想 (第 4 版)》
  • 《深入理解 Java 虚拟机(第 2 版)》
  • 《Effective java 中文版(第 2 版)》
  • 《Java 核心技术·卷 1:基础知识(原书第 9 版)》
  • 《Java 核心技术(卷 2):高级特性(原书第 9 版) : 高级特性》

.NET

  • 《精通 C#(第 6 版)》
  • 《深入理解 C#(第 3 版)》
  • 《CLR via C#(第 4 版)》

Python

  • 《集体智慧编程》
  • 《笨办法学 Python》
  • 《Python 基础教程》
  • 《Python 源码剖析》
  • 《Head First Python》
  • 《与孩子一起学编程》
  • 《Python 学习手册(第 4 版)》
  • 《Python Cookbook(第 3 版)》
  • 《Python 参考手册(第 4 版)》
  • 《Python 核心编程(第 3 版)》
  • 《Python 科学计算(第 2 版)》
  • 《利用 Python 进行数据分析》
  • 《Think Python:像计算机科学家一样思考 Python(第 2 版)》
  • 《Python 编程实战:运用设计模式、并发和程序库创建高质量程序》
  • 《Python 绝技:运用 Python 成为顶级黑客》
  • 《Flask Web 开发:基于 Python 的 Web 应用开发实战》

Android

  • 《Android 编程权威指南(第 2 版)》
  • 《移动应用 UI 设计模式(第 2 版)》

iOS

  • 《iOS 编程实战》
  • 《iOS 编程(第 4 版)》
  • 《Objective-C 高级编程》
  • 《Effective Objective C 2.0:编写高质量 iOS 与 OS X 代码的 52 个有效方法》

PHP

  • 《Head First PHP & MySQL(中文版)》
  • 《PHP 高级程序设计 : 模式、框架与测试》
  • 《深入 PHP:面向对象、模式与实践(第 3 版)》

C 语言

  • 《C 标准库》
  • 《C 和指针》
  • 《C 专家编程》
  • 《C 陷阱与缺陷》
  • 《C 语言接口与实现》
  • 《C 程序设计语言(第 2 版)》
  • 《C 语言参考手册(第 5 版)》

C++

  • 《C++ 标准库》
  • 《C++ 编程思想》
  • 《C++ 语言的设计与演化》
  • 《C++ 程序设计原理与实践》
  • 《C++ Primer (中文第 5 版)》
  • 《C++ 程序设计语言(第 1-3 部分)(原书第 4 版) 》
  • 《More Effective C++:35 个改善编程与设计的有效方法(中文版) 》
  • 《Effective C++: 改善程序与设计的 55 个具体做法(第 3 版)(中文版) 》

机器学习和数据挖掘

  • 《数据之巅》
  • 《矩阵分析》
  • 《机器学习》
  • 《统计学习方法》
  • 《机器学习导论》
  • 《推荐系统实践》
  • 《机器学习实战》
  • 《Web 数据挖掘》
  • 《深入浅出统计学》
  • 《模式分类(第 2 版)》
  • 《概率论与数理统计》
  • 《统计学习基础(第 2 版)(英文) 》
  • 《数据挖掘:概念与技术(第 3 版)》
  • 《数据挖掘:实用机器学习工具与技术(原书第 3 版)》
  • 《大数据:互联网大规模数据挖掘与分布式处理(第 2 版)》

数据库

  • 《SQL 应用重构》
  • 《SQL Cookbook》
  • 《高性能 MySQL (第 3 版)》
  • 《深入浅出 SQL(中文版)》
  • 《MySQL 技术内幕 : InnoDB 存储引擎(第 2 版)》
  • 《深入浅出 MySQL : 数据库开发、优化与管理维护》

测试

  • 《探索式软件测试》
  • 《有效的单元测试》
  • 《Google 软件测试之道》

项目与团队

  • 《人月神话》
  • 《快速软件开发》
  • 《人件(原书第 3 版)》
  • 《门后的秘密:卓越管理的故事》
  • 《极客与团队:软件工程师的团队生存秘笈》

求职面试

  • 《程序员面试金典(第 5 版)》
  • 《编程之美 : 微软技术面试心得》
  • 《金领简历:敲开苹果、微软、谷歌的大门》
  • 《剑指 Offer:名企面试官精讲典型编程题(纪念版)》

编程之外

  • 《暗时间》
  • 《数学之美》
  • 《赢得朋友》
  • 《精益创业》
  • 《批判性思维》
  • 《世界是数字的》
  • 《程序员的数学》
  • 《程序员健康指南》
  • 《禅与摩托车维修艺术》
  • 《关键对话:如何高效能沟通》
  • 《写作法宝:非虚构写作指南》
  • 《黑客与画家 : 来自计算机时代的高见》
  • 《软件随想录 : 程序员部落酋长 Joel 谈软件》
  • 《如何把事情做到最好:改变全球 9800 万人的人生指导书》

reference


2014-11-20 book , computer-science , network , linux

Nexus 5 不同版本

要给哥弄个 Nexus 5,网上一查有美版的 D820,还有国际版的 D821。顺手做个笔记LG D820 VS LG D821。两个版本的 LG Nexus 5 在几乎所有的配置和外观上都没有任何的区别,主要区别在通讯模块上,一个支持 GSM/CDMA/WCDMA/LTE,而另外一个不支持 CDMA,具体的支持情况外媒梳理如下:

##北美 Nexus 5 版本 (LG D820):

  • GSM: 850/900/1800/1900 MHz
  • CDMA: Band Class: 0/1/10(这个频段是中国电信也支持的,其实大多数有 CDMA 的国家都在这个频段范围内,所以是支持所有 CDMA 频段的)
  • WCDMA: Bands: 1/2/4/5/6/8/19
  • LTE: Bands: 1/2/4/5/17/19/25/26/41

##Nexus 5 国际版本,没有 CDMA (LG D821):

  • GSM: 850/900/1800/1900 MHz
  • WCDMA: Bands: 1/2/4/5/6/8
  • LTE: Bands: 1/3/5/7/8/20

D820 能够兼容 AT&T、T-Mobile 和 Sprint 的 2G、3G 和 LTE 网络;而 D821 则可兼容欧洲、亚洲等其余地区的网络频段。

D820 美版需要破解才能电信 4G,D821 支持联通 4G,中国移动所使用的是特有的频段,不支持

##D820(H)、D820(E)、D820(S) 区别

D820(H)、D820(E)、D820(S) 三者其实硬件都是一样的,就是 RAM 颗粒使用得不一样而已。 D820(H) 是 Skhynix(海力士)的 RAM 颗粒,D820(E) 是 Elpida(尔必达)的 RAM 颗粒,D820(S) 是 Samsung(三星)的 RAM 颗粒。查了下 LG 的内部资料,貌似 D820(S) 故障率最高,无故黑砖的同学警惕是否买到 D820(S) 的机器~

查看 D820(H)、D820(E)、D820(S) 方法~关机后,按音量“-”以及开机键同时开机,然后进 bootloader 查看~

参考:


2014-11-12 android , nexus , google , lg

Vim 插件之:vim-repeat

这个插件顾名思义,就是扩展了 vim 中 . 的功能,有些插件实现的复杂修改(比如修改 surrounding) 用原生的 . 无法实现,而用该插件可以实现。

Installation

Plug 'tpope/vim-repeat'

Usage

既然提到了 vim.repeat 就不得不提到 vim 的 . 操作。

  • 比如使用 diw 删除了一个 word,那么可以使用 . 来删除另一个 word
  • 如果使用 dd 删除了一行,那么可以使用 5. 来删除 5 行
  • 如果在 insert 模式下,输入 hello!,那么使用 ESC 进入 normal 模式,那么移动光标,在另外一个地方使用 . 可以快速输入 hello!

而如果使用 :help repeat 就会发现 vim 支持的 repeat,日常使用的 . 只不过是冰山一角。. 被叫做 single-repeat,vim 还支持

  • multi-repeat
  • complex-repeat
  • using-scripts

等等复杂的 repeat commands。

multi-repeat

vim 中的 multi-repeat 其实日常中也非常熟悉,比如 :2,5g/^$/d 这种类似的命令就被叫做 multi-repeat. 解释一下这个例子,就是从 2 到 5 行中匹配 ^$ (也就是空行) 的内容执行命令 d (删除)。

恢复到这个命令最原本的模式

:[range]g[lobal]!/{pattern}/[cmd]

这条命令的也是就是在行数范围 range 的行上,匹配 pattern 的行,执行 Ex command(默认是 :p)

:[range]g[lobal]/{pattern}/[cmd]

这条命令的也是就是在行数范围 range 的行上,匹配 pattern 的行,执行 Ex command(默认是 :p)

:[range]v[global]/{pattern}/[cmd]

:g!

几点说明:

  • 对于上面在 pattern 两边的 / 可以使用其他非字母单字节字符来替换,比如使用 \, ", |, 等,这种方式使得可以在 pattern 中直接使用 /
  • 对于这里的 cmd 是 vim 的 Ex cmd,使用 :help ex-cmd-index 来查看

常见的 Ex 命令

  • :d delete lines
  • :g execute commands for matching lines
  • :grep run ‘grepprg’ and jump to first match
  • :help
  • :insert
  • :ls
  • :m move lines
  • :new create a new empty window
  • :w write to a file
  • :wq
  • :x
  • :z

比如替换文本中所有 pat 为 PAT

:g/pat/s//PAT/g

同样也可以使用 :%s/pat/PAT/g

g 命令是一个非常强大的命令,更多的可以参考下一章节的 g 使用。

complex-repeats

更为复杂的 repeat ,那就需要使用到 vim 内置的 register 0-9a-zA-z"

q{0-9a-zA-z"}           " 来开启录制
q                       " 之后使用 q 来停止录制
@{0-9z-aA-Z".=*+}       " 执行 Register 中的内容,`%` 当前文件名,`#` 可选文件名,这两个 Register 不能使用
@@                      " 执行上一次

Power of g

delete all line match pattern

:g/pattern/d

delete all lines not match pattern

:g!/pattern/d
:v/pattern/d

copy all match lines to the end of file

:g/pattern/t$

move all match lines to the end of file

:g/pattern/m$

copy all lines matching pattern to register ‘a’

qaq:g/pattern/y A

说明:

  • qaq 清空 Register a
  • y A 是 Ex cmd (:help :y), yank the current line into register A (append to register a)

reverse entire file

:g/^/m0

reference


2014-11-03 vim , vim-plugin , tpope , vim-repeat

Google推出inbox的一点思考

前一天就看到Rumor说Google有一款inbox产品要发布,没想到今天一早就看到+Sundar Pichai 发了一Po 说发布这个产品了。第一时间申请了邀请码,可是到目前为止也没见邀请码的踪影,也就只能从一些介绍,截图,视频中看到一些端倪,也由此写下一些想法。 inbox with nexus 6

##改变 Gmail发布已有10年,这十年时间Gmail改变了人们使用邮箱的习惯,而这十年变化的东西太多了,邮箱这一概念早被人说是应该淘汰的东西,时至今日邮箱却依然还是日常生活,工作交流中很重要的一个环节,可是邮箱亟需要变革,不仅是作为用户而言,并且是邮箱服务提供商应该需要思考的问题,越来越多的垃圾邮件,越来越多的不必要的邮件出现在用户的收件箱。而今天Gmail团队给自己的服务一个evolution,虽然Gmail已经在不久前启用了分类服务,能够帮助过滤一些无用的邮件,但可能Gmail团队觉得还不够,他们要以一种智能的方式帮助用户收发邮件—-他们在官方博客上这样说:designed to focus on what really matters. 用户只需要关注他们真正需要关注的。改变总是好的,无论这个改变是好是坏,改变意味着不满足与现有的状态,期望以一种理想的状态而活着。所以无论这个服务是否会像waze失败,最后总会有收获inbox web design 图片来自Verge

##UI设计、功能变革 那就来看看这个服务让人耳目一新的功能,首先让人眼前一亮的就是UI的设计,无论是Web还是移动端,简直就是Material Design的推广,靓丽的颜色配合着无比流畅的动画,首先让使用者的体验就很爽朗。其次就是博客中宣传的:Bundles,Highlights,Reminders, Assists, and Snooze,这三个功能构成inbox的主体,虽然Bundles就是Gmail中的不同Tab分类,Highlights应该也就是Gmail中的星,Reminders,Assists,and Snooze也就是Gmail中的工作表,可是inbox给使用者的感受是不一样的,让我想到的第一个词语就是GTD,getting things done. 这个词我第一次接触是在本科上的一门校外选修课上老师讲的。邮箱的作用难道不是这个吗?原来我们转了大大的一圈又回到了邮箱最原始的作用,帮助工作生活交流,Gmail原来一种时间乱糟糟的顺序给我们安排,而inbox是以一种事情重要程度,get more import things done first.

##背后算法 说到inbox这里,就不免让我想起Google Now,想起Andrew Ng的机器学习,Google Now是Google推出的个人助手,机器学习是一门公开课,我们这学期也在学,inbox能够提供这样的一种服务,Google要在背后做的运算是及其大的,如果要做的更加智能要做的或许更多,一封邮件重要与否,一封邮件对于某一个个人重要与否,都需要背后很强大的算法计算得出。而同样你得提供更多的数据,所谓的给予的多,收获的更多。当然这只是我片面的想象,背后的数据谁也不知道,除非你去问Google的employee们。

##inbox展望 inbox作为Gmail的一个革新,无论如何我都是期待的。目前我还没用过还不知道真正的使用体验也就不好说什么了。只是Google各种产品的混乱逻辑也我也弄不清楚了,虽然Gmail一直有工作表这样的功能,但却把GTD的功能做的很烂,虽然之前的keep也有GTD类似的功能,却放在类似记事本一样的笔记类应用中。当然那些产品加上那些功能也不是多此一举,却一时间让人无法选择。我原本以为所谓的inbox应该是所有服务的一个inbox,当然Gmail是最最最重要的一个inbox,而Google+的通知呢?在Web上无处不在的通知难道不应该出现在inbox中?Blogger的评论呢?YouTube制作者的评论呢?或许那死了的Reader还有那个你关注的博客又更新了一篇文章呢?我原本以为的inbox是那样的,最后的结果是我真的想多了。 但转念一想,或许不久Google Now能够给我们提供吧,期待未来。


2014-11-02 Google , inbox , Gmail

手机信号字母表示

使用智能手机的朋友会发现,在手机信号旁边或者上面都会有一些奇怪的字母,比如3G、E、H等等,这些字母都代表什么意思呢?哪种网络状态速度最快?下面让我们详细了解一下吧!

  1. G指GPRS,它是GSM移动电话用户可用的一种移动数据业务,GPRS可说是GSM的延续,是2.5G网络。在iPhone手机上显示O;2.5G的速度约为10KB/s

  2. E指EDGE网络,是增强型数据速率GSM演进技术,属2.75G,速度约为20KB~30KB/s

  3. 3G指普通3G网络,在国内常见的3G有电信的CDMA2000、联通的WCDMA和移动的TD-SCDMA三种,速度在2-7M;

  4. H见于联通的WCDMA手机上,指3G的升级版HSDPA网络,是3.5G,速度可达14.4M;

  5. H+常见于中国联通的WCDMA手机上,hsdpa的升级版HSPA+,是3.75G,速度可达21M-42M;

从网络速度对比来看,从慢到快依次是 G<E<3G<H<H+

日常生活中,在使用手机的过程中,我们常常可以在屏幕的状态栏上方看到网络信号的标识,大概有G/3G/T/E/1X/H/H+这些信号标识,这些标志代表什么含义呢?

移动卡网络信号有:G、E、T(或者H)

China Mobile

G:G是GPRS通用分组无线服务技术(General Packet Radio Service)的简称,它是GSM移动电话用户可用的一种移动数据业务,GPRS可说是GSM的延续。GPRS的传输速率可提升至56甚至114Kbps,理论上资费较为便宜。具有高速数据传输速度10倍于GSM、永远在线、仅按数据流量计费的特点;

E:E是EDGE(Enhanced Data Rate for GSM Evolution)增强型数据速率GSM演进技术的简称,是一种从GSM到3G的过渡技术,GPRS到第三代移动通信的过渡性技术方案(GPRS俗称2.5G, EDGE俗称2.75G.)。现在中国移动的EDGE网络已经基本上覆盖全国,只有一些较为偏僻的地区无法访问,其传输速率在峰值可以达到384kbps,现在比较主流的无线网络传输方式;

T或者(H):T是TD-SCDMA(Time Division-Synchronous Code Division Multiple Access时分同步码分多址)的简称,其是中国提出的第三代移动通信标准(简称3G),也是ITU批准的三个3G标准中的一个以我国知识产权为主的、被国际上广泛接受和认可的无线通信国际标准。现在使用的版本是R4版本,理论下载数值为378.2KB/S。

移动卡的用户在信号不稳定时,手机可以在这些信号中自动转换,使你的手机基本通话要求得以保证不间断。

联通卡网络信号有:G、3G(或者H或者3.5G)、H+

unicom

G:这里不用介绍了,和移动的G是一样的,但是由于联通建的基站比较少,所以网络信号质量很差,大家都不愿意用了;

3G(或者H或者3.5G):HSDPA(High Speed Downlink Packet Access)高速下行分组接入,是一种移动通信协议,亦称为3.5G(3½G),它的下载速度理论呢是可以达到7.2Mbp/s。在国内的三大运营商中,联通的3G是做的最好的,很多人用;

H+:HSPA+的英文全称为 High-Speed Packet Access+,增强型高速分组接入技术,是HSPA的强化版本,最高的下行21Mbps,大部分HSPA+手机基本都是支持5.76Mbps的最高上行速度和21Mbps或者28Mbps的最高下行速度,相比较HSPA的速度更快。总的来说HSPA+比HSPA的速度更快,性能更好,技术更先进,同时网络也更稳定,是目前LTE技术运用之前的最快的网络!其属于联通3.75G网络,当前的联通3G网络覆盖较好。显示H+的时候网速是最快的,理论速率可以达到42Mbp/s的,也就是联通目前畅销的WO卡。

电信卡网络信号有:1X、3G

telecom

1X:1X即CDMA1x,也就是我们通常所说的电信的2G网络,CDMA1X手机上网的传输速率可达每秒钟144Kb,不过在现在的情况下,1X已经满足不了用户的需求了。不过电信2G(也就是1X)对比其它运营商的G属于是最稳定的,也是表现最好的信号;

3G:3G是指3G信号CDMA2000(EVDO.A),EV-DO是3G CDMA的技术名称,在手机上为了简便显示为3G,它的速率理论上达到3M,但实际上一般只有1.6M左右。它是基于移动网络的多址分发同时提供网络流量,这3家运营商的3G网络信号覆盖最好最广的就是电信的3G信号了,他的实测下载速度峰值可以达到290Kb/s左右,电信卡的资费理论上也比较便宜点;

reference


2014-10-24 Android , Knowledge

照片添加GPS信息

在玩Ingress之后的很长一段时间内,我觉得如果照片没有地理位置信息是一种缺失,而去年买的 Nikon 单反没有GPS模块,Nikon提供的GPS模块需要单独购买价格不便宜并且携带不方便,于是我找到一种既便宜又简洁的方式可以给照片添加上GPS信息。

需要借助的工具:

具体原理是:按照时间顺序,将手机记录的GPS信息写入相机拍摄的照片中。

具体步骤:

  1. 调校相机时间和手机时间保持一致
  2. 使用My Tracks应用记录GPS信息,保证在使用单反拍照前后一直在记录。所以最好的办法是出门前打开My Tracks,回家关闭记录。
  3. 回到家,导出照片,安装GeoSetter软件,将My Tracks记录的文件导出为gpx文件
  4. 打开GeoSetter,全选所有照片,在菜单中找到和GPS文件同步,快捷键Ctrl+G,找到Android手机中Export出的gpx文件,同步。
  5. Ctrl+S,保存。

之后GPS信息就被写到照片文件中了。


2014-10-02 DSLR , GPS , Nikon , 摄影

优化 Java 中正则表达式

Java 中和正则相关的工具类都在 java.util.regex 包下,Java 使用了 Nondeterministic Finite Automaton (NFA),之所以称为非确定性是因为当正则匹配给定字符串时,每一个字符都可能和正则匹配多次。这个匹配引擎被广泛的使用在 .NET, PHP, perl, Python, Ruby 中。很多人认为正则处理很快,很强大,但是其实不同正则表达式的写法可能导致消耗的时间和空间相差几十倍甚至上百倍,当在一些移动设备中使用正则时则要更加注意。

在引擎内部,NFA 使用回溯(backtracking) ,通常情况下针对给定的字符串,正则表达式可能有不止一种匹配方式,那么规则匹配引擎则会尽可能匹配所有可能,直到失败。

为了更好的理解 NFA 和回溯,举一个简单的例子,比如有一个正则表达式 sc(ored|ared|oring)x ,而输入的文本是 scared

在开始的时候,引擎会查找到 sc,立即找到匹配的前两个字符,接着会从第三个字符开始匹配 ored,发现不匹配则会尝试下一个可能 ared,这个匹配成功,继续匹配后面的 x,此时发现不成功,那么引擎会回溯回去匹配第三个可能 oring,同样也没有匹配。那么引擎会回溯到第二个字符开始继续匹配 sc,直到匹配到字符结尾,然后抛出匹配失败。

优化回溯

在上面的例子中就能看到,NFA 使用回溯来进行规则匹配,上面的例子也非常容易发现回溯的一个问题,就是即使是很简单的例子,也可能导致回溯非常多次。由此可以想象,当回溯失控时对应用程序的性能影响。因此优化正则表达式的一个很重要的部分就是尽量减少回溯的次数。

因为回溯的存在,在遇到现实复杂情况时,正则匹配可能需要花费大量时间来寻找完整的匹配。更糟糕的是,引擎花费大量的时间来匹配从而宣告一次失败,这个时间远比一次成功的匹配来得多。因此需要记住的是,当测试正则表达式的速度时,测试正则匹配不成功的时候,而不是测试成功的匹配。而当测试匹配时,则尽量使用刚刚好匹配的字符串,因为这种字符串花费最长的时间。

避免重新编译正则

当程序中需要不止一次使用相同的正则表达式时,预先编译好后使用。先使用 Pattern.compile() 定义好,而不是直接使用 Pattern.matches()matches() 方法内部每一次都会重新编译表达式。

并且记住对于不同的输入字符串,我们可以复用 Matcher 对象,不过要记住调用 reset() 方法。

合理使用括号

如果不需要引用括号内容,使用非捕获型括号 (?:PATTERN),节省捕获时间,减少回溯使用状态数量。只在必要时使用括号捕获。

不要滥用字符组

比如在 [Ff] 应当使用不区分大小写的匹配而不是字符组

准确表达意图

正则表达式提供很多结构(字符组,多选结构,量词等等),很多结构功能存在重叠,做同一件事情可能有不同的表达,这个时候应该选择最适当的结构。比如多选结构和字符组,多选结构完全覆盖了字符组。(a|b|c|d)[abcd] 匹配的文本是一样的,但是多选结构用于处理“可能出现若干表达式”,而字符组是专门用于处理“可能出现若干字符”的,这种情况字符组效率要远远高于多选结构。所以应当选择用 [abcd].

避免多选结构多个分支匹配相同文本

正则非常灵活,往往同一个表达式可能匹配多种不同形态的文本,但是如果一个表达式中包含若干”能匹配不同形态文本“的子表达式,那么子表达式能匹配的文本有重叠就可能有效率问题。

比如 a+a+,再比如 [0-9]+\w+ 前后连接部分产生重复匹配问题。

两条规则

  • 凡是 regex1*regex2*(量词不限于*) 的表达式,都要尽力避免 regex1 和 regex2 能匹配相同的内容
  • 凡是 (regex1|regex2) 的表达式,尽力避免 regex1 和 regex2 匹配相同的内容

使用起始终止锚点

除非是及其罕见的情况,否则以 .* 开头的正则表达式都应该在最前面添加 ^ 或者 \A 如果这个正则表达式在某个字符串的开头不能匹配,那么显然在其他位置它也不能匹配。添加锚点无论是手工添加还是通过优化自动添加都能够配合开头字符 / 字符串 / 字串识别优化,节省大量不必要的工作

在表达式前面独立出 ^ 和 \G

^(?:abc|123)(^abc|^123) 在逻辑上是等价的,但是许多正则引擎指挥对第一个表达式使用 开头字符 / 字符串 / 字串识别优化。所以第一种办法的效率高得多

在表达式结尾独立出 $

确定起止锚点能够提高匹配速度,如果使用了 $ 标记结尾,正则引擎会从符合条件的长度开始匹配,而略过目标字符串中其他不关心的字符。

暴露尽可能多的匹配部分

xx* 替代 x+ 能够暴露必须匹配的 x 同样,用-----{0,2}代替-{5,7}

th(?:is|at) 替代 (?:this|that) ,就能暴露出必须的 th。如果不同的多选分支的结尾部分相同,我们也可以从右面”提取”。例如 (?:optim|standard)ization

对于传统 NFA,一旦匹配到结果就会停止。

用字符组代替分支条件

比如对于想要匹配的 a 或 b 或 c 或 d,使用 [a-d] 而不要使用 (?:a|b|c|d)。字符组比使用分支条件速度快。

谨慎使用点号

谨慎使用点号,星号,加号这样的元字符,只要能确定范围,就不要用点号。只要能够预测重复范围,就不要使用量词。

别过分依赖正则

正则表达式确实很强大,但是不要过分依赖正则。

最常见的错误就是,只要字符串操作就能完成,但非要用正则。比如判定一个字符串以什么开头,或者什么结尾,或者判断是否包含某一个子串。

reference


2014-09-30 java , regex

log4j XML 配置

我们都知道 log4j 有两种配置文件的语法,本文主要介绍 XML 格式的配置格式。

log4j XML 配置的一些细节记录。

priority 和 level 的区别

我们都知道日志打印的级别,从低到高依次是 TRACE, DEBUG, INFO, WARN, ERROR and FATAL.

日常使用中经常会看到 root 或者 logger 节点配置 <level value="INFO"> 这样的语句,root 节点中也有 priority 的配置

<logger name="com.package">
    <level value="WARN" />
</logger>

<root>
  <priority value ="debug" />
  <appender-ref ref="console" />
</root>

定义了 priority 的 root 只会将 DEBUG 级别及其以上级别的日志发送到 Appender 中。logger 的 level 同理,只会将 WARN 级别和以上的日志发送到 appender 中。

他们的区别只在于 priority 在 root 中用,level 则 logger 中用。

appender 中 Threshold 的使用

appender 的配置

<appender name="fileAppender" class="org.apache.log4j.RollingFileAppender">
   <param name="Threshold" value="ERROR"/>
</appender>

假设有如下两种情况。

priority value="DEBUG" and param name="Threshold" value="ERROR"

priority value="ERROR" and param name="Threshold" value="DEBUG"
  1. 第一种情况 Logger 设置优先级 DEBUG,appender Threshold 设置为 ERROR,意味着 logger 会将 DEBUG,INFO,WARN,ERROR 和 FATAL 级别的日志发送到 appender,但是 appender 只会接受 ERROR 和 FATAL 的日志,所以最后日志中只会有 ERROR 和 FATAL 级别的日志。
  2. 第二中情况,logger 设置为 ERROR,appender 设置为 DEBUG,意味着 logger 会将 ERROR 和 FATAL 级别日志 pass 到 appender,而 appender 能够接受 DEBUG,INFO,WARN,ERROR,FATAL 级别的日志,但最后的日志中也只有 ERROR 和 FATAL 级别的日志。

所以两者的最后结果是一致的。组合二者的使用能够更有效率的打印测试环境或者生产环境的日志。

同一份日志打印到多个地方

定义不同的 appender ,然后在 logger 中定义多个在 pass 到 appender 即可。

不同的 package 使用不同的 appender

则在定义 logger 时 name 中指定对应的 package name,然后引用对应的 appender。

不同的 appender 相同的文件

log4j 不支持不同的 appender 打印到相同的文件中。

reference


2014-09-28 java , log4j , log4j12 , log4j12-config

正则表达式学习笔记

从开始接触正则到现在已经过去很多年了,然而依然没有完全学会正则,每一次回顾的时候总是有很多很多的新东西。

什么是正则,看中文非常抽象,而英文 regular expression 就好理解得多,regular expression 它是一个有规律,常规的,经常需要用的表达式,究其根本就是一个用来搜索特定字符串的表达式,这个表达式遵循一定的规律,有自身的逻辑表达,通过这种通用的方式可以写出比较容易理解的搜索语句。

根据维基百科的说明 正则一词是美国数学家 Stephen Cole Kleene 于 1950s 正式使用。而这个概念则是在 1980s 因为 Unix 下文本编辑器工具的使用而变得常见。自此之后正则的语法规则 POSIX 和 Perl 区别。

常用表达

表示或

gray|grey

表示匹配 gray 或者 grey 两个单词

分组,用来定义边界,或者确定执行顺序

gr(a|e)y

和上面表达等效

常见的定量表达

?       表示前面的字符出现 0 次或者 1 次
*       表示前面的字符出现 0 次或者多次
+       表示前面的字符出现 1 次或者多次
{n}     表示前面的字符出现 n 次
{m,}    至少 m 次
{m, n}  m 到 n 次

通配符 . 可以匹配任何一个字符

字符组 Character class

字符组 Character Class 是一个比较好理解的,就是一组字符,用方括号来标示,表示匹配其中某一个字符。比如常见的

[aef]
[0-9]
[a-zA-Z]

字符组中的范围表示使用的是 ASCII 编码中的码值,所以不能写成 [9-0]

排除型字符组,在方括号后增加 ^

[^0-9]       # 非 0-9
[^ae]       # 非 a 或 e

字符组简记法,常见的字符组,比如数字,英文字符组,可以用简单的缩写形式来表示。

\d      [0-9]

元字符 meta-character

比如字符组中的 - 还有括号 [, ] 还有常见的 ^, $ 这些特殊意义的字符都是元字符。如果遇到想要匹配这些特殊的字符就需要转义。

^
$
.
[]
[^]
*
()
{}
\b          单词边界
\d          [0-9]
\w          字母数字下划线和汉字
\s          任意空白

后向引用

当用小括号指定子表达式后,匹配这个子表达式的文本(分组捕获)会自动拥有一个组号,从左到右,分组的左括号为标志,出现的第一个分组为 1,其后 2,3,4 类推。

后向引用则可以利用分组捕获的文本来匹配比如重复的单词

\b(\w+)\b\s+\1\b

其中的 \1 在表示引用前面 (\w+) 括号中捕获的文本,比如 go go 则会被匹配。分组捕获通常用在想要获取匹配字符串中部分子串时使用。

但是在使用捕获时一定要注意,过多的捕获会影响正则表达式的效率,如果不需要捕获则可以使用

(?:exp)

来忽略捕获的内容。

分组还有一些其他的语法

(?<name>exp)        匹配 exp,将捕获的文本放到名字为 name 的组,也可以写成 (?'name'exp)
(?#comment)         注释,无任何作用

零宽断言

了解零宽断言需要分两部分来理解,第一是匹配宽度为 0,第二断言表示满足一定的条件。匹配宽度指的是匹配时占字符宽度,比如在匹配不包含 a 或 b 开头的单词时,如果使用 [^ab] 那么 [] 则会占用一个字符宽度。零宽断言用于查找在某些内容(但并不包括这些内容)之前或之后的东西时。

零宽断言的英文是 Lookahead and Lookbehind Zero-Length Assertions 这就好理解很多了,就是正则表达式先要匹配的内容往前或者往后的断言,也就是比如我想要匹配的一串数字必须在 id= 后面就可以使用先行断言

(?=id=)\d+

零宽断言又分四种

(?=exp)         断言自身出现的位置的后面能匹配表达式 exp
(?<=exp)        断言自身出现的位置的前面能匹配表达式 exp
(?!exp)         断言此位置的后面不能匹配表达式 exp
(?<!exp)        断言此位置的前面不能匹配表达式 exp

先行断言

先行断言,也叫零宽度正预测先行断言 (?=exp) 表示匹配表达式前面的位置

比如,b\w+(?=ing\b) ,匹配以 ing 结尾的单词的前面部分(除了 ing 以外的部分)

注意:先行断言的执行步骤是这样的,先从要匹配的字符串中的最右端找到第一个 ing(也就是先行断言中的表达式)然后再匹配其前面的表达式,若无法匹配则继续查找第二个 ing 再匹配第二个 ing 前面的字符串,若能匹配则匹配

例如: .*(?=ing) 可以匹配 cooking singing 中的 cooking sing 而不是 cook

后发断言

后发断言,也叫零宽度正回顾后发断言 (?<=exp) 表示匹配表达式后面的位置

例如 (?<=abc).* 可以匹配 abcdefg 中的 defg

注意:后发断言跟先行断言相反,它的执行步骤是这样的:先从要匹配的字符串中的最左端找到第一个 abc(也就是先行断言中的表达式)然后 再匹配其后面的表达式,若无法匹配则继续查找第二个 abc 再匹配第二个 abc 后面的字符串,若能匹配则匹配

例如 (?<=abc).* 可以匹配 abcdefgabc 中的 defgabc 而不是 abcdefg

负向零宽断言

负向零宽断言 (?!exp) 也是匹配一个零宽度的位置,不过这个位置的“断言”取表达式的反值,同样,负向零宽断言也有“先行”和“后发”两种,负向零宽后发断言为 (?<!exp)

比如说想要匹配文本中所有等号后面的数字,但是就是不想匹配 id=123 这样 id= 开始的数字

(?<!id)=\d+

这四个断言的中文翻译的太烂了,完全不知道说的什么,用英语解释就清晰很多。

Atomic groups

Atomic groups 光看字面意思完全无法理解,但是如果举例说明,比如

a(bc|b)c

这是一个普通的分组正则,可以匹配 abcc 或者 abc,但是

a(?>bc|b)c

使用 Atomic groups 之后则只能匹配 abcc 而不能匹配 abc.

Atomic groups 在匹配 abc 时,括号中匹配到 bc 就退出了,而此时无法匹配括号外的 c 则失败了。

Atomic groups 会查找到第一个匹配的子串,然后就退出匹配,也不会回溯。所以如果在一些匹配到第一项,而后面不需要考虑的情况下可以使用 Atomic groups。

实例

比如说字符串 foobarbarfoo:

bar(?=bar)     finds the 1st bar ("bar" which has "bar" after it)
bar(?!bar)     finds the 2nd bar ("bar" which does not have "bar" after it)
(?<=foo)bar    finds the 1st bar ("bar" which has "foo" before it)
(?<!foo)bar    finds the 2nd bar ("bar" which does not have "foo" before it)

组合使用:

(?<=foo)bar(?=bar)    finds the 1st bar ("bar" with "foo" before it and "bar" after it)

表示匹配 bar 要求前面是 foo 而后面是 bar,那么就匹配第一个 bar 了。

Look ahead positive (?=)

Find expression A where expression B follows:

A(?=B)

Look ahead negative (?!)

Find expression A where expression B does not follow:

A(?!B)

Look behind positive (?<=)

Find expression A where expression B precedes:

(?<=B)A

Look behind negative (?<!)

Find expression A where expression B does not precede:

(?<!B)A

Atomic groups (?>)

An atomic group exits a group and throws away alternative patterns after the first matched pattern inside the group (backtracking is disabled).

  • (?>foo|foot)s applied to foots will match its 1st alternative foo, then fail as s does not immediately follow, and stop as backtracking is disabled

A non-atomic group will allow backtracking; if subsequent matching ahead fails, it will backtrack and use alternative patterns until a match for the entire expression is found or all possibilities are exhausted.

  • (foo|foot)s applied to foots will:

    1. match its 1st alternative foo, then fail as s does not immediately follow in foots, and backtrack to its 2nd alternative;
    2. match its 2nd alternative foot, then succeed as s immediately follows in foots, and stop.

网页

匹配网页标题

<head>([^<]+)</head>

然后取分组 1

网页图片

<img\s+[^>]*? src=['"]?([^"'\s]+)['"]?[^>]*>

取分组 1

身份证

简单版本,不精确

[1-9]\d{14}
[1-9]\d{14}\d{2}[0-9xX]

reference


2014-09-27 regex , regular-expression , java , python , nlp

log4j 根据 package 打印日志到不同目的地

log4j 可以配置不同的包打印到不同的 appender 中,通过在配置中添加如下配置。

<!-- 这里的 additivity 配置了该 package 下的 appender 是否需要传递到 root , 默认为 true , 造成日志打印两遍 -->
<logger name="com.jutils.appender.LogLevelATest" additivity="false">
  <level value="INFO"/>
  <appender-ref ref="consoleAppender"/>
</logger>
<logger name="com.jutils.appender.LogLevelBTest" >
  <level value="WARN"/>
</logger>

定义 logger 在 name 中指定需要 include 的 package full path,然后在 appender-ref 中指定需要打到的 Appender 中。


2014-09-27 log4j , log4j12 , log4j12-conf , log4j12-xml

电子书

本站提供服务

最近文章

  • Glance 个人自定义 Dashboard Glance 是一个可以自行架设的个人 Dashboard 以及 RSS 订阅信息面板。
  • Fileball 一款 iOS tvOS 上的媒体播放器及文件管理器 Fileball 是一款 iOS,tvOS 上的本地文件管理器,本地音乐播放器,本地视频播放器,以及文本编辑器,Fileball 可以在 iPhone,iPad,Apple TV 上使用。Fileball 可以连接网络共享,支持 SMB,FTP,SFTP,Synology,NFS,WebDAV 等,支持 Emby,Jellyfin 等,还可以连接百度网盘,Box,Dropbox,Google Drive,OneDrive,pCloud 等,可以作为 [[Infuse]] ,[[VidHub]] 等播放器的平替,高级版本价格也比较合适。Fileball 也支持 [[IPTV]]。
  • 在日本申请入台证材料及在线提交注意事项 本文记录入台证办理的材料及提交手续,以及在使用线上提交系统的时候需要注意的点。入台证是中华民国台湾地区出入境许可证的俗称,所有进入台湾的人都需要申请此许可证。
  • 从 Buffer 消费图学习 CCPM 项目管理方法 CCPM(Critical Chain Project Management)中文叫做关键链项目管理方法,是 Eliyahu M. Goldratt 在其著作 Critical Chain 中踢出来的项目管理方法,它侧重于项目执行所需要的资源,通过识别和管理项目关键链的方法来有效的监控项目工期,以及提高项目交付率。
  • AI Shell 让 AI 在命令行下提供 Shell 命令 AI Shell 是一款在命令行下的 AI 自动补全工具,当你想要实现一个功能,敲一大段命令又记不住的时候,使用自然语言让 AI 给你生成一个可执行的命令,然后确认之后执行。