上手正则表达式(一)

引言 在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。 与通配符(如*)类似,正则表达式也是用来进行文本匹配的工具,不过他要更为精确和复杂。学习正则表达式的最好办法就是利用例子学习。 元字符 现在考虑从英文小说里查找hi,你可以使用正则表达式hi,但这样的代价是你会查找到文本中所有有hi的位置,而不是一个单词。为了查找到一个单词你可以使用\bhi\b,他会帮你匹配单词hi存在的位置。 \b是正则表达式中元字符(metacharacter),代表单词的分界处,但请注意\b并不匹配用来分界单词的字符(如空格,标点或者换行符),他匹配的是一个位置。 更为精确的说法是:\b匹配一个前一个字符和后一个字符不全是\w的位置。 这样的元字符在正则表达式中有很多,他们帮助构建了正则表达式强大的匹配能力。你不需要全部记住,可以在使用中进行查阅,并在实践中掌握他们。 如果你要寻找这样的一个字符串:A单词后面跟着一个B单词,AB中间可以有任意字符存在。可以使用\bA\b.*\bB\b。 这里的.和\*也是两个其他的元字符。.可以匹配除了换行符之外的任何字符,而*比较特殊,他使得前面的内容可以连续重复使用任意次来匹配字符串。 如果你学过离散数学或者计算理论,应该对*不会太过陌生(尤其是学过计算理论),之后你还会看到+元字符,他们的区别和你在离散数学中他们的区别相同。 下面给出常见的元字符,和使用他们的一些例子 元字符 说明 . 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线或汉字 \s 匹配任意的空白符 \d 匹配数字 \b 匹配单词的开始或结束 ^ 匹配字符串的开始 $ 匹配字符串的结束 现在我们可以回顾一下\b的精确描述,理解\w的存在。 例子 \ba\w+\b 匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母 a,然后中间至少有一个字母或者数字(\w+),最后是单词结束处(\b)。用到了\w与+的共同使用,*可以有0,但+至少一个。 \b\w{6}\b 匹配刚好六个字符的单词 ^\d{5,12}$ ^ 和 $保证了是整个字符串的匹配,而不是字串,{5,12}代表重复的次数不能少于5次,不能多于12次,否则都不匹配。

<span title='2022-01-17 15:18:16 +0800 CST'>January 17, 2022</span>&nbsp;·&nbsp;yunlang

Datalab实验记录

CSAPP:Data Lab 记录 bitXor(x,y) 使用两种运算实现异或操作(&与~),要求指令数最多为14 //1 /* * bitXor - x^y using only ~ and & * Example: bitXor(4, 5) = 1 * Legal ops: ~ & * Max ops: 14 * Rating: 1 */ int bitXor(int x, int y) { int nx = ~x; int ny = ~y; int fx = x & ny; int fy = nx & y; return ~( (~fx) & (~fy) ); } 采用的是离散数学中亦或的另一种定义方式,$$P \oplus Q = (P \wedge \neg Q) \vee (\neg P \vee Q)$$....

<span title='2021-12-17 11:14:14 +0800 CST'>December 17, 2021</span>&nbsp;·&nbsp;yunlang

C语言的声明

前言 编程语言的类型模型(type model)一直都是编程语言学习的重点。虽然但是,C语言声明的语法实在是过于奇怪,以至于我们需要花费一些时间认真理解一下,首先思考一下简单的类型模型,考虑下面的C语言声明: typedef char * string; string punchline = "I'm a frayed knot"; 可以将其分为两部分:变量的类型和变量来理解 被称作 是 变量的类型 string char * 变量 punchline “I;m a frayed knot” C语言声明的产生 C语言中的声明器(declarator) 简单地说,声明器就是标识符以及和他组合在一起的任何指针、函数符号、数组下标(本表额外添加了初始化内容) 数量 C语言中的名字 C语言中出现的形式 零个或多个 指针 const volatile;volatile;; const; * volatile const 有且只有一个 直接声明器 标识符;标识符[下标];标识符(参数);(声明器) 零个或一个 初始化内容 = 初始值 声明器是一个很模糊的概念,一个简单的思考方式是C语言的声明器是声明中缺少类型以及对类型限定后剩下的部分,这也可以理解 int *p,*q,r 都是什么类型了(p,q是指针,r是int型变量) C语言的声明 声明增加了至少一个类型说明符(包括类型说明,存储说明和类型限定符),声明器(一个或多个,逗号分割)分号(语句结束)但也请注意,合法的声明存在限定条件,举例说明: 函数的返回值不能是一个函数,所以 foo()() 是非法的 函数的返回值不能是一个数组,所以 foo()[] 是非法的 数组里面不能有函数,所以 foo 是非法的 你也许很快想到,针对这些问题可以用指针解决,所以 函数的返回值允许是一个函数指针,如 int(* fun()) () 函数的返回值允许是一个指向数组的指针, 如 int(*foo())[] 数组里面允许有函数指针 如 int (*foo[])() 数组里面允许有其他数组,所以你经常看到 int foo[][] 优先级规则 C语言声明的优先级规则是阅读C语言声明关键的一步:因为C语言的声明并不是简单的从左到右,下面给出这条规则...

<span title='2021-12-13 23:36:06 +0800 CST'>December 13, 2021</span>&nbsp;·&nbsp;yunlang

C++下的四种cast转换方法

前言 C++有四种显式类型转换方法,分别是dynamic_cast, reinterpret_cast, static_cast, const_cast。 他们的使用方法为 dynamic_cast <new_type> (expression) reinterpret_cast <new_type> (expression) static_cast <new_type> (expression) const_cast <new_type> (expression) 与之相对,我们也回忆一下传统的类型转换方法 (new_type) expression new_type (expression) 下面就四种类型转换进行简单介绍。 dynamic_cast 有需要提前指出的是,dynamic_cast运算符更多是用来实现RTTI(运行时类型识别 run-time type identification) 功能,其中dynamic_cast用来将基类的指针或引用安全地转移成派生类的指针或引用。 使用RTTI时必须加倍小心,更多时候最好定义虚函数,使用时程序员必须清楚地知道转换的目标模型并且必须检查类型转换是否被成功执行。 dynamic_cast只用在指向类的指针,引用(或void *)上。这种转换允许upcast(从派生类向基类的转换)也能downcast(从基类向派生类的转换),这时需要转过去的指针所指向的目标有效且完整。 举例说明 #include<iostream> #include<exception> using namespace std; class Base {virtual void dummy() {} }; class Derived : public Base { int a; }; int main() { try { Base * pba = new Derived; Base * pbb = new Base; Derived * pd; pd = dynamic_cast<Derived*>(pba); if( pd == 0 ) cout << "Null pointer on first type-case....

<span title='2021-12-08 19:36:06 +0800 CST'>December 8, 2021</span>&nbsp;·&nbsp;yunlang