🌓

正则表达式

正则引擎

正则引擎主要可以分为两大类:一种是DFA,一种是NFA。这两种引擎都有了很久的历史(至今二十多年),当中也由这两种引擎产生了很多变体!于是POSIX的出台规避了不必要变体的继续产生。这样一来,主流的正则引擎又分为3类:一、DFA,二、传统型NFA,三、POSIX NFA。
DFA 引擎在线性时状态下执行,因为它们不要求回溯(并因此它们永远不测试相同的字符两次)。DFA 引擎还可以确保匹配最长的可能的字符串。但是,因为 DFA 引擎只包含有限的状态,所以它不能匹配具有反向引用的模式;并且因为它不构造显示扩展,所以它不可以捕获子表达式。
传统的 NFA 引擎运行所谓的“贪婪的”匹配回溯算法,以指定顺序测试正则表达式的所有可能的扩展并接受第一个匹配项。因为传统的 NFA 构造正则表达式的特定扩展以获得成功的匹配,所以它可以捕获子表达式匹配和匹配的反向引用。但是,因为传统的 NFA 回溯,所以它可以访问完全相同的状态多次(如果通过不同的路径到达该状态)。因此,在最坏情况下,它的执行速度可能非常慢。因为传统的 NFA 接受它找到的第一个匹配,所以它还可能会导致其他(可能更长)匹配未被发现。
POSIX NFA 引擎与传统的 NFA 引擎类似,不同的一点在于:在它们可以确保已找到了可能的最长的匹配之前,它们将继续回溯。因此,POSIX NFA 引擎的速度慢于传统的 NFA 引擎;并且在使用 POSIX NFA 时,您恐怕不会愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索,而非较长的匹配搜索。
使用DFA引擎的程序主要有:awk,egrep,flex,lex,MySQL,Procmail等;
使用传统型NFA引擎的程序主要有:GNU Emacs,Java,ergp,less,more,.NET语言,PCRE library,Perl,PHP,Python,Ruby,sed,vi;
使用POSIX NFA引擎的程序主要有:mawk,Mortice Kern Systems’ utilities,GNU Emacs(使用时可以明确指定);
也有使用DFA/NFA混合的引擎:GNU awk,GNU grep/egrep,Tcl。
举例简单说明NFA与DFA工作的区别:
比如有字符串this is yansen’s blog,正则表达式为 /ya(msen|nsen|nsem)/ (不要在乎表达式怎么样,这里只是为了说明引擎间的工作区别)。 NFA工作方式如下,先在字符串中查找 y 然后匹配其后是否为 a ,如果是 a 则继续,查找其后是否为 m 如果不是则匹配其后是否为 n (此时淘汰msen选择支)。然后继续看其后是否依次为 s,e,接着测试是否为 n ,是 n 则匹配成功,不是则测试是否为 m 。为什么是 m ?因为 NFA 工作方式是以正则表达式为标准,反复测试字符串,这样同样一个字符串有可能被反复测试了很多次!
而DFA则不是如此,DFA会从 this 中 t 开始依次查找 y,定位到 y ,已知其后为a,则查看表达式是否有 a ,此处正好有a 。然后字符串a 后为n ,DFA依次测试表达式,此时 msen 不符合要求淘汰。nsen 和 nsem 符合要求,然后DFA依次检查字符串,检测到sen 中的 n 时只有nsen 分支符合,则匹配成功!
由此可以看出来,两种引擎的工作方式完全不同,一个(NFA)以表达式为主导,一个(DFA)以文本为主导!一般而论,DFA引擎则搜索更快一些!但是NFA以表达式为主导,反而更容易操纵,因此一般程序员更偏爱NFA引擎! 两种引擎各有所长,而真正的引用则取决与你的需要以及所使用的语言!

特殊字符

1
2
(转义字符)若要匹配这些特殊字符之一,在字符前面加反斜杠字符 (\)。 
例如,若要搜索“+”文本字符,可使用表达式“\+”。

元字符 行为 示例 /* 零次或多次匹配前面的字符或子表达式。
等效于 {0,}。 zo/* 与“z”和“zoo”匹配。 + 一次或多次匹配前面的字符或子表达式。
等效于 {1,}。 zo+ 与“zo”和“zoo”匹配,但与“z”不匹配。 ? 零次或一次匹配前面的字符或子表达式。
等效于 {0,1}。
当 ? 紧随任何其他限定符(/*、+、?、{n}、{n,} 或 {n,m})之后时,匹配模式是非贪婪的。
非贪婪模式匹配搜索到的、尽可能少的字符串, 而默认的贪婪模式匹配搜索到的、
尽可能多的字符串。 zo+ 与“zo”和“zoo”匹配,但与“z”不匹配。 ^ 匹配搜索字符串开始的位置。 如果标志中包括 m(多行搜索)字符,^ 还将匹配 \n 或 \r 后面的位置。
如果将 ^ 用作括号表达式中的第一个字符,则会对字符集求反。 ^\d{3} 与搜索字符串开始处的 3 个数字匹配。
[^abc] 与除 a、b 和 c 以外的任何字符匹配。 $ 匹配搜索字符串结尾的位置。 如果标志中包括 m(多行搜索)字符,^ 还将匹配 \n 或 \r 前面的位置。 \d{3}$ 与搜索字符串结尾处的 3 个数字匹配。 . 匹配除换行符 \n 之外的任何单个字符。 若要匹配包括 \n 在内的任意字符,请使用诸如 [\s\S] 之类的模式。 a.c 与“abc”、“a1c”和“a-c”匹配。 [] 标记括号表达式的开始和结尾。 [1-4] 与“1”、“2”、“3”或“4”匹配。 [^aAeEiIoOuU] 与任何非元音字符匹配。 {} 标记限定符表达式的开始和结尾。 a{2,3} 与“aa”和“aaa”匹配。 () 标记子表达式的开始和结尾。 可以保存子表达式以备将来之用。 A(\d) 与“A0”至“A9”匹配。 保存该数字以备将来之用。 | 指示在两个或多个项之间进行选择。 z|food 与“z”或“food”匹配。 (z|f)ood 与“zood”或“food”匹配。 / 表示 JScript 中的文本正则表达式模式的开始或结尾。
在第二个“/”后添加单字符标志可以指定搜索行为。 /abc/gi 是与“abc”匹配的 JScript 文本正则表达式。
g(全局)标志指定查找模式的所有匹配项,i(忽略大小写)标志使搜索不区分大小写。 | 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。 \n 与换行符匹配。 ( 与“(”匹配。 \ 与“”匹配。

元字符

1
下表包含了多字符元字符的列表以及它们在正则表达式中的行为。

阅读全文

聊一聊职业发展

目录

老生常谈,再谈谈测试职业发展

有这么个普遍现象

测试招聘者,特别是一、二线互联网公司的招聘者最苦恼的事儿就是招人。想找到一个合适的人难于上青天,每天各种撒网,简历看几百份,面大几十人,能捞到一个中意的小伙伴就谢天谢地了。但同时很多测试小伙伴发现找工作很难,特别是进大一点的厂,他们特别挑:代码要会写,要有软件架构能力,问一大坨平时根本用不到的技术问题,还挑经验,挑沟通能力,挑这挑那,有时候还特么挑学历、挑年龄。。。 供求总难以匹配起来,造成了双方都很痛苦。

Why?

能力要求不匹配是最核心的问题。软件、互联网近20年来飞速成长,其实也经历了很多阶段。行业软件兴盛阶段和外包兴盛阶段(2000-2010年)行业进入了大量的测试人员,当时最主流的测试实践是:重心放在系统验收阶段。测试人员的主要工作基本都投入在了基于业务的黑盒测试上,对代码能力、系统理解的能力要求不多。2010年后,互联网行业的真正兴起让国内软件开发模式开始缓慢调头,快速迭代的模式逐步兴起,开发周期越来越短,迭代越来越快,但系统越来越越庞大、复杂。原来的测试工作模式和工作范围越来越无法满足要求了。但大量从业人员技能范围转变是一件很难的事情,行业是有巨大惯性的。从宏观上看大量QA技能转变跟不上需求转变是造成市场供求不匹配的主要原因

So What?

三个观点:1. 只做手工测试,不懂系统实现的测试工程师的职业发展会越来越受限。2. 能够转型成适应市场需求的同学将在近几年的时间获得超额回报(因为市场供不应求,企业不得不抬高价格来寻找这样的人)。3.对于个体来说,自我成长永远最重要,自己永远要对自己的发展负责,别依赖外部环境,自己想办法变成市场的香饽饽才靠谱。

到底什么样的人抢手?

按照我一点理解讲一讲什么样子的人会抢手吧,限于篇幅会偏重技术角度来讲。个人之见,欢迎讨论和拍砖。

高段位要求(高级职位需求)

例子2:上面的问题,除了环境,还有一个槽点:开发提测质量不高。测试的头几天,很多主流程都走不通,导致测试总是在等待,或者是跟着开发一起联调。而这段时间,已经被习惯性的认为是测试时间了,因为:提测了。

你推动了:测试提供冒烟用例,开发必须完成一定程度的自测才能提测。
你推动了:测试和开发做自动化同期共建,在开发过程中,核心功能就被自动化用例保护起来了。
你推动了:开发切分feature提测,而不是攒一个大招一下子提一坨。
你推动了:代码Codereview变成团队常规活动,QA在早期跟进核心代码,把问题坑杀在萌芽阶段。
你推动了:外部资源联调非常早的进行,不会让它在测试后期成为测试blocker。
。。。

例子3:你发现测试时间长,QA自己也有问题。

你推动了:有明确的测试计划,并让所有干系人都有明确的预期。
你推动了:测试依据风险测试,最大的风险得到最快的cover,科学分配时间,明显缩短bug反馈时间弧。
你推动了:bug严格管理,所有重要bug都及时修复。
你推动了:良好的沟通和汇报机制,每天让团队主要干系人清晰的知道,距离发布还差多远。

阅读全文

提高数据库业务代码性能的几种技术手段

navicat中的explain单条查询语句的性能分析。 阿里云混合云数据库管理HDM方案利用阿里云提供的混合云,无侵入的方式监控数据的各项性能和指标。 sqlprofiler工具的机制是在本机启动一个拦截服务(127.0.0.1:4040),本机的开发环境需要将jdbc连接串修改为指向该ip和端口,拦截服务获取sql后,传递给数据库并执行,从而统计出相关数...

阅读全文

有感于一个悬而未决的问题

我们新开启了一个项目。项目仍然使用tomcat作为容器发布,但是这次出现了高CPU占用的情况,当然使用了ssl证书,但是我们仍然遵照了生产其他tomcat的配置方式,使用的是apr(最初是nio,导致cpu资源无法释放)。这个tomcat还出现过几次假死。也在发现假死后把堆栈都输出以发现情况具体在哪里。但是,都没有解决。由于是我在摆弄部署的事,研发leade...

阅读全文

菜鸟变专家:经典计算机图书

“如果能时光倒流,回到过去,作为一个开发人员,你可以告诉自己在职业生涯初期应该读一本,你会选择哪本书呢?我希望这个书单列表内容丰富,可以涵盖很多东西。”

很多程序员响应,他们在推荐时也写下自己的评语。以前就有国内网友介绍这个程序员书单,不过都是推荐数 Top 10的书。其实除了前10本之外,推荐数前30左右的书籍都算经典,伯乐在线整理编译这个问答贴,同时摘译部分推荐人的评语。下面就按照各本书的推荐数排列。

(1) 《代码大全》史蒂夫·迈克康奈尔

推荐数:1684

code complete 代码大全

“优秀的编程实践的百科全书,《代码大全》注重个人技术,其中所有东西加起来,就是我们本能所说的“编写整洁的代码”。这本书有50页在谈论代码布局。” —— Joel Spolsky

对于新手来说,这本书中的观念有点高阶了。到你准备阅读此书时,你应该已经知道并实践过书中99%的观念。– esac

(2)《程序员修炼之道》

推荐数:1504

Pragmatic Programmer 程序员修炼之道

对于那些已经学习过编程机制的程序员来说,这是一本卓越的书。或许他们还是在校生,但对要自己做什么,还感觉不是很安全。就像草图和架构之间的差别。虽然你在学校课堂上学到的是画图,你也可以画的很漂亮,但如果你觉得你不太知道从哪儿下手,如果某人要你独自画一个P2P的音乐交换网络图,那这本书就适合你了。—— Joel

(3)《计算机程序的构造和解释》

推荐数:916

Structure and Interpretation of Computer Programs 计算机程序的构造和解释

就个人而言,这本书目前为止对我影响醉倒的一本编程书。

《代码大全》、《重构》和《设计模式》这些经典书会教给你高效的工作习惯和交易细节。其他像《人件集》、《计算机编程心理学》和《人月神话》这些书会深入软件开发的心理层面。其他书籍则处理算法。这些书都有自己所属的位置。

然而《计算机程序的构造和解释》与这些不同。这是一本会启发你的书,它会燃起你编写出色程序的热情;它还将教会你认识并欣赏美;它会让你有种敬畏,让你难以抑制地渴望学习更多的东西。其他书或许会让你成为一位更出色的程序员,但此书将一定会让你成为一名程序员。

同时,你将会学到其他东西,函数式编程(第三章)、惰性计算、元编程、虚拟机、解释器和编译器。

一些人认为此书不适合新手。个人认为,虽然我并不完全认同要有一些编程经验才能读此书,但我还是一定推荐给初学者。毕竟这本书是写给著名的6.001,是麻省理工学院的入门编程课程。此书或许需要多做努力(尤其你在做练习的时候,你也应当如此),但这个价是对得起这本书的。

阅读全文

crontab 在GUI环境下执行webdriver

Linux下,大部分的问题都跟环境有关。crontab也不例外。我的需求:crontab定时执行脚本,依据条件启动webdriver(selenium)去浏览器上做一些操作,而且是周期性的。我使用的是splinter框架驱动业务。 需要解决:1、系统具备gui运行的环境。 1yum install -y libXfont xorg-x11-fonts* 2...

阅读全文

Tomcat整体架构浅析

转自:https://blog.csdn.net/cx520forever/article/details/52743166
tomcat详解搭配着看:https://www.cnblogs.com/kismetv/p/7228274.html

comment:本文基于Tomcat7.0.68

1.整体结构

架构图:
这里写图片描述

1.1各组件解释:

从顶层开始:

一般情况下我们并不需要配置多个Service,conf/server.xml默认配置了一个“Catalina”的

1
<Service>


Tomcat将Engine,Host,Context,Wrapper统一抽象成Container。
Connector接受到请求后,会将请求交给Container,Container处理完了之后将结果返回给Connector
下面看Container的结构:
这里写图片描述

这里写图片描述
Standard/*XXXX/*是组件接口的默认实现类。

Tomcat 还有其它组件,如安全组件 security、logger、session、naming 等其它组件。这些组件共同为 Connector 和 Container 提供必要的服务。

1.2组件的生命线Lifecycle

Tomcat中很多组件具有生命周期,如初始化、启动、关闭,这些组件的生命周期具有共性,因此Tomcat中将其抽象为接口Lifecycle,来控制组件的生命周期,它通过 事件机制 实现各个容器间的内部通讯。
Lifecycle接口的方法:
这里写图片描述
继承关系图:
这里写图片描述

阅读全文

【计算机理论基础】二进制与数、字

计算机底层说到底是一堆电路,一个电路只有2种状态:通和不通。N个电路就可以有2^N次个状态的组合,它们排列组合成一个序列。
这个序列被人设的,按照规则进行了解释。
一堆无序的排列组合需要赋予人类世界的意义,所以确立了二进制到符号(字符、数字)的规则。
符号是被认为携带意义的感知。
意义就是一个符号可以被另外的符号解释的潜力。符号之间解释的链,即可达到信息交换的目的。

我们学习就是要理解这种既定的规则。

人类世界沟通和交流用的是语言和符号,不同母语的国家交流需要翻译。计算机与人类传递信息,需要翻译。

主要(目前我的理解深度而言)两大类:

尽管在计算机内部,数字的表象被包含在字符内,也就是字符集中有可以表示数字的字符,但从作用上来说,表象和实质还是有差异。从代码上来看差异:

1
2
3
4
5
int a=124;
string b="124";
char c='124';
//没写过程序的人看到124,认为他们是一个东西。但是在计算内部,却是3种信息。
//代码写的是人,但是传递给计算机处理的时候,负责解释这些字符的是编译器。

理解byte

计算机中一个电子元件的状态是1bit(通或不通),而人设的规定存储信息的最小单元是一个字节即 8 个 bit,即1byte。
这里byte的意义有两种:

它组合是:
00000000-11111111
被解释为10进制的0-256(2^8次方)种变化的信息量。

数的规则

主要围绕着二进制如何被解释为数,或者反向的数如何用二进制来表达。

数分配的存储资源大小

Java中八种基本数据类型:short、int、long、float、double、boolean、byte、char。每种类型都按传统规定了存储在计算机当中占据空间的大小,好比限定了装载这些数的盒子。

阅读全文

shell中各种括号的作用详解()、(())、[]、[[]]、{}

①命令组。括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。 ②命令替换。等同于cmd,shell扫描一遍命令行,发现了(cmd)结构,便将 ( c m d ) 结 构 , 便 将(...

阅读全文

图灵机的逻辑等价形式——lambda演算简介

译者述

才疏学浅,非数学专业,翻译尽量尊重原文,如有纰漏,海涵。

论文摘要

这篇论文是一篇简短易懂的lambda演算介绍。λ-calculus(lambda演算)是Alonzo Church开创,最初是作为研究数学函数的可计算性的相关属性的工具,随着它的流行,其逐渐成为函数编程语言家族强有力的理论基础。这篇简介展示了利用lambda演算如何构建算数和逻辑的数学计算,以及如何定义递归函数(尽管lambda演算子中的函数是匿名的,因此它们不能被显示引用,我们仍然可以定义递归函数)。

1 定义Definition

lambda演算子可以说是世界上最小的通用编程语言。lambda演算子由一个单一转换规则(变量替换,通常被叫做β-conversion,β变换)和一个单一函数定义系统构成。它在1930年代被Alonzo Church作为一个方法引入有效计算能力的概念的形式化中。lambda演算子是通用的,是因为任意可计算函数可以使用此形式表达和求值。因此它等价于图灵机(这也是为什么我费劲翻译原文的原因)。尽管如此,lambda演算子强调的是符号变换规则的使用,却并不关心实际机器是如何实现这些规则的。这是一个更接近软件而不是硬件的方法。

lambda演算子的核心概念是“表达式”(“expression”)。一个“名字”,也被叫做“变量”,是一个标示符,它可以是任意字母a, b, c… 一个表达式可能只是一个名字或者可能是一个函数(function)。函数使用希腊字母λ来来表示函数变量的名字。函数体(body)指定变量名如何排列。身份函数(The identity function),例如:字符串(λx.x)可以代表一个身份函数,字符串中的“λx”告诉我们函数的变量是“x”,“x”是被函数体不做任何改变的返回了。

函数可以被其他的函数使用。比如,函数A被用在了函数B中,可以写为“AB”的形式。注意在本文中,大写的字母被专门用来表示函数。实际上,Lambda演算中任何元素都可是函数,就连数字或者逻辑值都使用可以相互作用的函数来表示,它们是通过符号的字符串转换成另一种符号的字符串达到目的的。所以Lambda演算中没有类型一说,任何函数可以作用于其他函数。开发者的责任是保证计算指令的合理性。

表达式被第归的定义如下:

1
2
3
4
5
6
7
8
9
< expression > := < name >|< function >|< application >
< function > := λ < name > . < expression >
< application > := < expression >< expression >

译文形式
<表达式> := <标识符>|<函数>|<应用>
<函数> := λ<标识符> . <表达式>
<应用> := <表达式><表达式>
译者注:应用(application )即给函数一个(实际)参数进行求值

表达式可以使用括号来包裹以达到清晰表示的目的,比如“E”为一个表达式,”(E)“是等效的(译者加了引号)。另外,这门语言中仅有的两个关键字是”λ “和”.”。为了避免将带括号的表达式混淆,我们约定:函数应用从左边开始关联(左结合),也就是下方的组合表达式:

E 1E 2E 3 . . . E n 可以被下面连续表达式所表示: (…((E 1E 2)E 3) . . . E n)

从 λ表达式的定义可见,一种优雅的函数表现形式是之前出现过的的字符串,带括号或者不带括号:

λx.x ≡ (λx.x)

阅读全文