正则表达式中的非获取匹配
正则表达式是代码中的常用技巧,主要用来匹配符合某种句法规则的字符串。常用的正则表达式本文不再赘述,详细可以参考wiki(Python,Java)。本文主要讨论的是非获取匹配的正则表达式。
常见的非获取匹配有以下几种:
(?:pattern) 主要用来匹配pattern但不获取结果。我们看下面的例子。
>>> re.match("win (7|vista)", "win 7").group() 'win 7' >>> re.match("win (7|vista)", "win 7").groups() ('7',) >>> re.match("win (?:7|vista)", "win 7").group() 'win 7' >>> re.match("win (?:7|vista)", "win 7").groups() ()
可以看出,使用这种模式括号中匹配内容并没有存储供以后使用。它是比“win 7|win vista”更加简便的形式。
以上是Python的示例,Java代码如下(以后的例子不再赘述):
Pattern ptn = Pattern.compile("win (7|vista)"); Matcher m = ptn.matcher("win 7"); while (m.find()) { for (int i = 0; i <= m.groupCount(); i++) { System.out.println(m.group(i)); } }
(?=pattern) 正向肯定预查。它在任何匹配pattern的字符串处查找字符串,它仅仅是检查是否匹配,而不将预查的结果包含其中。当然,它也是非获取匹配。看个例子就明白了。
>>> re.match("win (?=7|vista)", "win 7").group() 'win ' >>> re.match("win (?=7|vista)", "win 7").groups() ()
(?!pattern) 正向否定预查。例子如下:
>>> re.match("win (?!7|vista)", "win 8").group() 'win ' >>> re.match("win (?!7|vista)", "win 8").groups() ()
(?<=pattern) 反向肯定预查。查找某个字串之前是否满足pattern。
>>> re.search("(?<=95|98)win", "98win").group() 'win' >>> re.search("(?<=95|98)win", "98win").groups() ()
(?<!pattern) 反向否定预查。
>>> re.search("(?<!95|98)win", "7win").group() 'win' >>> re.search("(?<!95|98)win", "7win").groups() ()
现在我们来看实际中的需求。现在我有一个字符串,这个字符串是由中文和英文组成,现在我要把这个字符串切成一个个只由中文或者英文组成的字串。比如说将“McCulloch与Pitts将神经系统”切成”McCulloch“、“与”、“ Pitts“、”将神经系统“。
首先要知道匹配中文的正则是”[\u4e00-\u9fa5]“,在Python中,我们可以使用findall方法:
reg = re.compile(u"[\u4e00-\u9fa5]+|[A-Za-z]+") print "\t".join([w for w in reg.findall(u"McCulloch与Pitts将神经系统")])
对于Java,除了使用这种方式匹配,我们还使用刚刚说过的非获取匹配来达到同样的效果。对于需求的句子,可以看到要切分的地方,要么是中文接英文,要么是英文接中文。所以我们在反向肯定预查到中文然后正向肯定预查到英文处调用split操作,或者在反向肯定预查到英文正向肯定预查到中文处调用同样的操作。于是有:
Pattern ptn = Pattern.compile( "(?<=[\u4e00-\u9fa5])(?=[A-Za-z])|(?<=[A-Za-z])(?=[\u4e00-\u9fa5])", Pattern.UNICODE_CASE); String[] words = ptn.split("McCulloch与Pitts将神经系统"); for(String word: words) { System.out.print(word + "\t"); }
可以看到达到了一样的效果,但是,在我的测试中,此法对Python中的正则库中的split方法并不适用。所以我们解决问题确实需要灵活多变的策略。
最后,我们再讨论以下js的实现。对于js来说,由于js不支持反向预查。所以,用和Python方法类似的简单策略。我们使用加上“g“修饰符的match方法(表示全局匹配,而不是只匹配一次)。
var testStr = "McCulloch与Pitts将神经系统"; var regExp = /[\u4e00-\u9fa5]+|[A-Za-z]+/g; testStr.match(regExp).forEach(function(i){ document.write(i+" "); });
windows下安装opencv
opencv(open source computer vision library)是一个基于C/C++语言的开源图像函数处理库。
它的主要模块包括:
- cv —— 核心函数库
- cvaux —— 辅助函数库
- cxcore —— 数据结构与线性代数库
- highgui —— GUI函数库
- ml —— 机器学习函数库
opencv是跨平台的,支持包括windows、unix以及android等平台。下图是英文wiki上一张关于opencv概述的图。关于opencv的一系列功能以及特性,本文不再赘述,如果要了解,请移步至opencv的中文站点介绍。
本文将会讲解在wndows上如何使用VS2010安装opencv,并以一个简单的程序作为结束。opencv在近期推出了2.3版本,不过本文仍然以2.2版本为例。其他安装请参考中文安装页面。
用PIL实现滤镜
本来想写一个系列,已经有了第一篇《用PIL实现滤镜(一)——素描、铅笔画效果》。最后关于各种滤镜的计算方法,分系列写实在是乏善可陈。
目前,由于Python语言限制,有些算法的效率十分低下(比如油画——oil painting)。在完成全部预计的效果之后,会再考虑优化效率。其实做这个东西完全是学习之用,估计也没有什么太大的实用价值:)
现在,代码已经托管在bitbucket上,如果你感兴趣,可以查看wiki。要获得代码,运行命令:
$ hg clone http://bitbucket.org/chineking/pil-filter-extension
代码中都有详细的注释,具体细节请参考代码。
用PIL实现滤镜(一)——素描、铅笔画效果
在计算机图形学发展史中,真实感绘制一直是主旋律。不过从20实际90年代中期开始,非真实感图像绘制(Non-Photorealistic Rendering,NPR)逐渐成为一个研究热点。说白了,真实感绘制目标是像照片般真实地再现客观世界,而非真实感图像绘制专注于图形个性化和艺术化的表达,它主要用来表现图形的艺术特质,以及模拟艺术作品(甚至包括作品中的缺陷)。
在介绍完非真实感图像绘制之后,我们再来提及一下PIL——Python Imaging Library(官方网址)。相信使用python的朋友们都不会陌生,因为在web应用中我们常常用它来生成缩略图。从名字也可以看出,PIL主要用来处理图片,它支持多种图片格式,并提供强大的图片和图像处理能力。详细的关于PIL的内容大家可以参阅手册。
这个系列,我们就主要使用PIL来进行滤镜方面的处理,包括素描、铅笔画、油画等等滤镜效果的实现。在以后我会把代码托管出来。
黑白反转游戏
声明:这篇文章中涉及的游戏来自@陈荣峰ayuLemon的创意,文章的主要目的还是研究这个游戏其中的算法,我所写的网页版的游戏版本也仅仅是为了验证算法的正确性。说明这个是防止大家误认游戏乃我的原创。本来原作者要求我不能在他的算法出来之前发出此文,我百思不得其解。我认为这个没有先后顺序,思前想后,还是发出来了。仅讨论之用。
事情的起因是这样的,在我又度过了一个不眠之夜、正打算睡觉之时,看到@python4cn 转发了一个同学的微博,原文是这样的:
@陈荣峰ayuLemon:用python做了个小游戏,这是5*5方格。每点击上面的方格一次,就改变周围四个方格和被点击方格的颜色,对于任意n*n方格,可否通过若干次点击使方格的颜色与最初完全相反??(3*3和4*4的都很容易~~这个5*5的似乎有困难) 大家帮忙想一想,证明行或者不行,哪些行,哪些不行~~
本来已经很困的我看到这个,又勾起了我的好奇。于是拿起纸笔,开始演算。当然首先从2×2开始,一直到4×4,确实没有什么困难。到5×5,算了很久才算出一个结果。
在分析这个问题之前,如果你想试玩,我做了一个网页版的,地址在这里。