TP正则表达式原理和实例详解(一)
为了对照的方便,目录设置跟TP帮助一样。
1.概述
“*?”这两个是最常用的通配符了,其实也是最简单的正则表达式,前者是任意个字符,后者是一个字符,在微软资源管理器中就可以用这两个符号,常用软件的搜索项中大多也支持。在Word中也是有类似的表达式的,如“^?”是任意字符、“^#”是任意数字、“^p”是回车等。TP的特色就是对汉字的支持,在2.2通配符中可以看到很多支持特定汉字的通配符。
除了对汉字的支持外,TP最大的特色是自定义替换和批量正则替换,也正由于这两大功能,使得处理词库可以做到千变万化,处理百万大词库的速度是一般专用软件所不能及的。
2.正则表达式的构成
一个正则表达式可以由几个分支构成,分支之间由“|”隔开,“|”必须是半角符号,如果对表达式的部分内容进行区分,就要用子表达式(见2.4子表达式),就是用括号括起来。分支只能查找项使用,不能在替换项中使用分支。
实例:
①你有一个词库,在每个词条的后面标有词条的字数,如:
×××× ××××× 5
×××× ×× 2
……
如果你要查找3字和4字的词条,你应在查找处输入:
3$|4$
“$”是行末,意思就是3结尾或者4结尾的词条。
②如果上面的例子中数字是用中文数字表示的,并且有的词条没标字数,如:
×××× ××××× 五
×××× ××× 三
×××× 十三
……
如果用“三$|四$”去查,肯定把“十三”的词条也查进去了,在“三、四”前面应该有空格,而“十三”的“三”前面是没空格的,我们就要用这个把他们区别开来。应把表达式写成:
\s(三$|四$)
“\s”是空白字符,这里是指空格,整句的意思就是:空格后面有“三”或“四”结尾的词条。前面有什么问题就不大了,当然写成“^.*\s(三$|四$)”意思还是一样的,“^.*”就是词条前任何内容。
省去括号就不行了,如改成“\s三$|四$”,一种情况是:空格“三”结尾的词条,另一种是单独“四”结尾的词条,这样十四、二十四等词条也包含在里面了。
2.1特殊符号
在词库整理中,“^、$、\t”比较常用,TAB字符在替换项中也可以使用,由于空格在批替换中不好使用,更加突出了“\t”的重要性,另外用TAB字符作为间隔符,便于在电子表格中进行处理。但是极点格式的词库是用空格来隔离编码和词条的,所以空格和TAB字符需要经常转换的。
在前面已经讲了“$”的运用例子,这里讲一个运用“^”的例子。如有一编码在前的极点格式词库,你要在每个编码前加上一个z,只要在
查找处输入:“^”,在替换处输入:“z”就可以了。
2.2通配符
在通配符中最常用的是“. \a \c \d \s”,分别代表任意字符、字母、汉字、数字、空白字符,这几个一定要牢记。范围要小,是汉字的要尽量用\c,是字母一定要用\a,是TAB字符就尽量用\t。
在批替换中空格只能用\s来表示,因为空格在批替换表中,被定义为查找和替换表达式的间隔符。
如:
aawt 工作
这样极点格式的词条,可以用这样的正则表达式来描述:
^\a+\s\c+$
其中+是任意多个至少一个的意思,整句的解释是:
行开始+多个字母+一个空白符(这里是一个空格)+多个汉字+行结束
2.3字符集
方括号里的字符串,只代表其中的一个,里面字符彼此之间是“或”的关系。
如有一个极点格式的拼音码表,你要其中以“vui”开头的特殊编码和词条删除,你只要
在查找处输入:
^[vui].*$
在替换处输入:
\d
进行替换即可
“^[vui].*$”的意思就是以vui之一的字母开头后面为任意内容的编码词条,“\d”的意思就是把查找的内容替换为空,同时把换行符也删除,如果没有\d就会留下一个空行。
既然是“或”的关系,字符集就可以用分支来表述,以下三个表达式的意义是一样的:
^[vui].*$
^(v|u|i).*$
^v.*$|^u.*$|^i.*$
好好理解这三条表达式,对掌握分支、子表达式和字符集有很大的助益。
如果你要在上例这个拼音码表中只留下以“vui”开头的特殊编码和词条,查找的内容要改为:
^[^vui].*$
在方括号内加个“^”就是“非”的意思,这个表达式就是指的是非vui开头的编码词条。
2.4子表达式
子表达式在前面已经讲到了,如:\s(三$|四$)、^(v|u|i).*$,也就是帮助中说的区分优先级的作用。在括号内用“|”分隔的内容,就是用来区分优先级的子表达式,实际原理跟字符集差不多的,结合正则表达式构成和字符集内容就好理解了。
另一个作用是引用,这是最精要的东西,很多批量正则替换表都要用到。
简单的理解就是,在前面用括号括起来的内容(子表达式),后面按顺序用“/”加数字表示引用前面匹配的内容。
我在解决坛友的问题中有一个查找叠词的例子,在这里分析几个词型:
学习学习(ABAB) 可以表示为:(\c\c)\1
(\c\c)就是任意代表双字词,\1就是代表前面的双字词。这里要注意不能把“(\c\c)”理解为“AA”的形式,(\c\c)不能匹配“呵呵”、“嘿嘿”,两个“\c”是不同的汉字,如要实现AA型的效果,就应该是:(\c)\1。
笑嘻嘻(ABB) 可以表示为:\c(\c)\1
一心一意(ABAC) 可以表示为:(\c)\c\1\c
以上的叠词是最
简单的引用,复杂的例子一定要注意“顺序”,如:
现在有“社会主义4现代化3建设2”这样类型的词条,也就是复合词里面标上单纯词的字数:
在查找处输入:
^(\f+)\~f(\f+)\~f?(\f*)\~f?(\f*)\~f?(\f*)\~f?(\f*)\~f?(\f*)\~f?(\f*)\~f?(\f*)$
在替换处输入:
\1\2\3\4\5\6\7\8\9
进行替换就把词条中数字全部去掉了,其他英文等单字节字符全部可以去除。
在查找表达式中,其中“\f+”就是一个以上双字节字符,当然包括汉字,“\~f”是一个非双字节字符。因为是复合词所以至少有两个单纯词构成,所以前面是“^(\f+)\~f(\f+)”,这样避免了查找替换单纯词条,后面是“~f?(\f*)”构成,就是可有可无。
整句查找表达式的意思就是查找2至9个单纯词加字数构成的复合词。
引用表达式必须按顺序与子表达式严格对应,“\1”必然是引用第一个括号里的内容,依次类推,“社会主义4现代化3建设2”中“\1”就是引用“社会主义”、“\2”引用“现代化”、“\3”引用“建设”,“\4”以后的内容未查找到匹配内容,引用为空,所以最后就会剩下“社会主义现代化建设”。
引用表达式数量应小于等于子表达式数量,在此例中替换处内容如改为:
\1\3
那么替换结果就是“社会主义建设”,就是只留下第一、三表达式的内容。
在TP中子表达式不能超过9个,此例中复合词一般不会超过9个单纯词,没什么问题,其他出现超过9个的情况怎么办呢,大家可以去参考一些我的一些优化、去优化等例子。
2.5重复指示符
关于复制指示符要注意两个方面的问题:
一是至少匹配一次与可以不匹配之间的区别
“\c\c\c?\c?”前面两个必须有,后面两个可以没有,所以是代表2-4个汉字,相当于\c{2,4}。
可有可无与至少一次的明确在于确定查找的范围,不要养成喜欢用“?、*”不确定重复指示符的习惯,该明确一定要明确,这样既能保证查找的准确性,另外在处理百万级词库和批替换表比较繁复时可以提高速度。在上一节处理复合词的例子中,查找表达式中开头用的就是“^(\f+)\~f(\f+)”,避免了对单纯词的查找,毕竟复合词是少数,如果加上“?、*”就会对单纯也进行空的替换,处理量要不知大上多少倍。
关于准确性,大家看了这个例子就明白了:
把二笔码表中带有的“,./;”标点编码的词条找出来,查找表达式应该是:
^\a\~f*\p\~f*\s.+$
首先“\a”就表示第一个肯定是字母,二笔只有声母才是首码
其次,后三码中有一个是“,./;”半角标点“\p”,就是我们要找的了,在它的前后都有可能有编码,所以要带“*”,而且也不能确定是字母还是标点,所以应该
是“\~f”单字节字符,连起来就是可有可无、可多可少的单字节字符“~f*”。
这里“\~f”后面一定要带“*”,“\p”后面一定不能带“?、*”,这就是准确性的要求。
最后,“\s.+”也应该是确定的,因为空白符肯定要有,编码以后词条也肯定要有。至于行首标志就不用说一定要有,且只能有一个,行末标志要看情况了,因为.+已经把后面一切都包括了,但一般还是要写上,这样完整些,不容易出错。
二是匹配次数尽可能多和尽可能少的区别
一般在词库处理中,由于很都很短,很少会用到匹配次数尽可能少的情况,但是重码多行长的时候就会用到,主要是用在文本类长行处理中。其实在TP在文本处理中运用很广,下面就是关于文本处理匹配次数的实例:
很多网络文章的双引号是英文双引号“"”
在查找处输入:
"(.{-})"
替换处输入:
“\1”
进行替换就可以转为全角引号。
如果在查找处输入的是:“"(.*)"”,这样每段只替换首尾,因为是最大范围的查找,中间所有的英文引号也包括进去了。
[ 本帖最后由 vu 于 2007-8-15 11:32 AM 编辑 ]
------------
替换表达式
替换表达式比较少,主要是对查找内容的引用、插入特殊字符、删除字符和格式的转换。在这里初学者一定要注意,替换表达式与查找表达式的区别,查找表达要区别种类繁多的字符,表达式要比替换表达式多得多。
查找表达式能在替换表达式中用的是子表达式,如:
在查找处输入:(\c\c)\c\1
在替换处输入:\1
那么查找到的是“学习再学习”的话,就会替换为“学习”,也就是说“\1”在查找处和替换处都是代表前面的“\c\c”。
极个别表达式在查找和替换是一样的,如:\t都是代表TAB字符,但是查找到的TAB字符不能在替换处用\t来表示引用,其实在替换处用\T或者其他表达式来表示TAB符都是可以的。
fficeffice" />
3.1 特殊字符
特殊字符主要分为三类:
一是引用类:可以用“\”加数字进行部分引用(就是子表达式),也可以用“\0”和“\&”进行完全引用。如把前面的例子改成:
在在查找处输入:(\c\c)\c\1
在替换处输入:\1-\&
则结果样式是:学习-学习再学习
二是插入类:\n(回车符)和\t(TAB符)比较常用。这两个相当于间隔符,分别用来区别行和行内字符块。
正则表达式是不能跨行处理的,那么要跨处理的时候怎么办呢?可以先去除回车符然后再恢复回车符,要注意分成一小段一小段地处理,如果整块文字只有一个回车,处理十万级以上的词库机器会吃不消的。在这方面有很多技巧待以后讲实例地时候再行讲解。
三是
删除类:\b(前删)和\d(后删),用得较多的是后删符,当然具体要根据实际情况而定。
如有这样的一段含有假回车的文字:
正则表达式是不能跨行处理的
,那么要跨处理的时候怎么办
呢?可以先去除回车符然后再
恢复回车符。
在查找处输入:\c$
在替换处输入:\d\&
这样可以把假回车删除,\c$意思行末汉字,\d\&就是把假回车删除然后再写上查找内容,这是向后删除的例子。
如果你要的就是这样块状的文字,可是有一个逗号在行首不好看,要把逗号、句号改在行末。可以这样:
在查找处输入:^(,|。)
在替换处输入:\b\&\n
^(,|。)意思就是标点形头的行,\b\&\n就是向前删除一个字符,把回车删除,然后重写查找的内容就是标点,再插入回车就完成了。
在实际运用中处理这种网络格式的文字比较复杂方法也很多,要看你源文字的格式和目标格式是什么而定,在这里只是说明一下删除表达式的运用。
3.2 替换函数
替换函数在原帮助中说得比较清楚了,对与字母格式的转换在码表中用得也很少,我在这里不详解了,在自定义替换表替换函数中再作详细说明。
总的来说,查找表达式做的是找到要处理的文字内容,替换表达式就是处理找到的内容,可以说是“米”跟“炊”的关系。 [ 本帖最后由 vu 于 2007-10-26 08:35 PM 编辑 ]
4. 自定义替换功能
自定义替换是TP的精髓之一,很多朋友对自定义替换理解不透,我想主要是要多看实例。关于自定义替换表如何操作我在前面的帖子里已讲了很多,不重复了,这里就讲讲原理和运用。
fficeffice" />
有这样的一个拼音码表:
中 zhong
国 guo
人 ren
……
对下面的词库进行自定义替换
中国
中国人
国人
……
结果是:
zhongguo
zhongguoren
guoren
……
为什么会是这样呢?其实很好理解,首先把“中”替换成“zhong”,然后再替换“国”,只是简单的批量字符替换而已,只是自动一条一条地处理,下面要讲的批量正则替换也是这个道理,只是它换成了表达式。如果里面有一条是“中国人民”那结果会是“zhongguoren民”,因为民字未进行替换,假定码表里没有民字。
全是编码(在这里是拼音)当然不是大家想要的,如果要实现这样的结果:
中zhong国guo
中zhong国guo人ren
国guo人ren
……
就得把自定义替换表改成:
中 中zhong
国 国guo
人 人ren
……
同样的道理就是把“中”替换成了“中zhong”。
对于编码来说这样的格式更实用:
中国 zhongguo
中国人 zgren
国人 guoren
……
这就有求于批
量正则替换了,单用自定义替换是没法做到的。
对于批量正则替换比较好理解,前面已经讲了道理跟自定义替换是一样的,就是多次查找替换任务集中在一起完成。
在WORD中查找替换太多了就用宏来处理,批量正则替换也是一样的,对于一些繁复的操作一条一条替换是不可想象的,在以前的帖子里很多替换表的内容我自己都记不住了,现在我们只要记一个一个的表就简单多了。
对于自定义替换表和批量正则替换表,查找内容和替换内容要用空格或Tab符隔开,也就是中间要有空白,查找内容和替换内容本身不能有空格。
要把这样的码表:
zhongguo中国2
zhongguoren中国人3
guoren国人2
……
变成:
中国 zhongguo
中国人 zhongguoren
国人 guoren
……
如下面的替换表是不合法的:
^(\~f ) (\ f+).* \2 \1
^$ \d
第一次替换意思是把行首“^”词“(\~f )”和编码“(\ f+)”对调位置,替换为编码在前“\2”在前词条“\1”在后,中间插入空格,并删除后面的多余内容。
第二条意思是删除去空行。
这里的问题就出在第一次替换,替换表达式中多了个空格,\2和\1之间不能有空格,可以在中间加个TAB符表达式,变成这样:
^(\~f ) (\ f+).* \2\t\1
^$ \d
等码表处理完毕了,可以在TP进行实际替换把TAB符替换为空格,其实TAB功能比空格强,这样转到电子表格很好处理,但是最终还是要变成空格的,所以最好能有专门的空格表达式,现版没有,建议下版能能增加空格表达式。
对于编码来说,自定义替换结合批量正则替换是最适合不过了,从这个帖子的标题中就可以看出其中的重要性了。但是现在还不能举这样的例子,因为要用到自定义替换表的替换函数,这是下一节的内容了。
[ 本帖最后由 vu 于 2007-10-26 09:03 PM 编辑 ]
4.1 在查找/替换中使用自定义替换表
上一节讲到把以下内容设自定义替换表1:
中 zhong
国 guo
人 ren
……
通过点击编辑>自定义替换>自定义替换表1,对以下内容进行处理:
中国
中国人
国人
……
结果是:
zhongguo
zhongguoren
guoren
……
这是自定义替换表的最原始用法,高级的用法是在查找/替换中使用自定义替换,最高级的用法是在批量替换表中使用。以上步骤在查找/替换中的用法是:
在查找处输入:(\c)
在替换处输入:\T{\1}
(\c)意思是把任一汉字设子表达式
\T{\1}意思是把子表达式1(查找到的汉字)由自定义替换表1进行替换,因为查找的是任意汉字,就对每个字进行替换了。
前面已经提到替换函数了,这里对自定义替换表替换
函数进行解释:
函数的表达式是:\Tn{…}
其中:\为表达式提示符,T表示自定义替换函数,n为自定义替换表的序号,大括号内的内容是函数的替换参数,也就是自定义替换表要处理的对象,可以是具体内容也可以是表达式。
前面例子中的\T{\1},因为是替换表1,可以把1省略了,当然写成\T1{\1}也是可以的。
用到两个以上替换表的情况也是有的,一种是处理复杂内容时必须用到多个自定义替换表,别一种是为了调试的方便,就多设几个替换表,省得改来改去。
对于自定义替换表比较大的,应及时地去除,否则下次启动时会占很大的资源,因为每次启动TP替换表的内容都是自动加载的。
替换参数相对难懂一点,大括号里的内容,就是我们要进行自定义替换的,如果大括号里面的内容是一个“中”字,那么\T{中}就是对“中”进行自定义替换,结果就是“zhong”,如果在上例中:
在查找处输入:(\c)
在替换处输入:\T{中}
结果是:
zhongzhong
zhongzhongzhong
zhongzhong
……
也就是把每个查找到的汉字都替换成了“zhong”。
如果替换处内容是:\T{\1},这样\1就是前面查到的汉字,如果查到的是“人”,就在自定义替换找到对应的是“ren”,这样每个字对应的是自己的匹配项。
对一些简单的处理,可以不用子表达式,也就是查找处不用括号,在替换处替换参数写作\0即可。上例可以这样执行替换:
在查找处输入:\c
在替换处输入:\T{\0}
还想简单的话,就省去替换参数,就剩下\T行了。
这是懒方法,在多个自定义替换表情况下就不行了,还有很多情况要使用子表达式替换的,如在上例中要达到这样的效果:
zhongguo 中国
zhongguoren 中国人
guoren 国人
……
可以这样完成:
在查找处输入:^(\c)(\c)(\c?)
在替换处输入:\T{\1}\T{\2}\T{\3}\t&
^(\c)(\c)(\c?)意思是二字词或者三字词,因为最后一个汉字是有问号的就是可有可无。
\T{\1}\T{\2}\T{\3}\t&意思是分别对查找到的汉字进行自定义替换,然后插入TAB符,最后重写一遍查到的内容,也就是查到的二、三字词。其中的\1、\2和\3分别对应查找中的三个括号,这在子表达式中已经学过的了。
现在这是全拼的编码,我们要把三字词,变成“首码+首码+全码”的格式,也就是要得到这样的结果:
zhongguo 中国
zgren 中国人
guoren 国人
……
这里就要引入一个过滤的概念,过滤就是对自定义替换表的内容进行筛选,现在我们要首码,在此例中就是拼音的第一字母,我们在此例中的自定义替换表1的内容是:
中 zhong
国 guo
人 ren
……
现在我们只要第一个字母就是z、g、r……,把拼音描述成:(\a)(\a*),就是一个字母加任意个字母,在设置自定义替换表中,把(\a)(\a*)写入过滤内容中,把以下内容设为批量替换表:
^(\c)(\c)$ \T{\1}\T{\2}\t&
^(\c)(\c)(\c) \T{\1}[1]\T{\2}[1]\T{\3}\t&
进行批替换后,就可以实现三字词的“首首全”格式的编码了。
第一条就是对二字进行全码编码。
第二条替换内容的[1]指的是自定义替换表中替换内容的第一个子表达式,在这里就是第一个字母。
用过滤的方式进行编码很简单,但我并不推荐用,一个是对初学者理解起来难,第二是操作起来麻烦,要手工填一下过滤表,很不方便。
反正通过批量替换都可以实现的,也就省去过滤这个步骤了。
基础知识介绍到这里结束了,要完全吃透,我认为还是要多写多试,一些正则表达式和替换规则就如同棋规,内容并不多,但是在具体运用中技巧就千变万化了。比如在五笔编码中,我写的多个批量替换表也是有差别的。在下一步我就全讲实例了。
[ 本帖最后由 vu 于 2007-10-26 08:57 PM 编辑 ]
-------
实例讲解(一)
首先讲的第一个是最常用的五笔格式编码的批替换表,过去对五笔格式编码的替换表介绍过,今天换一个全新的编法,自定义替换表还是要单字在前、编码在后的单字码表,批替换表如下:
^(.)(.?)(.?).*(.)$ \T{\1}1\T{\2}2\T{\3}3\T{\4}4\t&
(..).+123(..).+4\t(.*) \1\2\t\3
(.).+1(.).+23(..).+4\t(.*) \1\2\3\t\4
(.).+1(.).+2(.).+3(.).+4\t(.*) \1\2\3\4\t\5
详细解释:
^(.)(.?)(.?).*(.)$ \T{\1}1\T{\2}2\T{\3}3\T{\4}4\t&
#这个替换表的最大特点就是全部采用了任意通配符“.”,这样就可以用任意编码对任意字符进行编码了。
#查找部分分解:^为行首,(.)第一字符为确定字符,(.?)(.?)是第二三个字符可有可无,.*中间相隔任意个字符,(.)$最后结尾的一个确定字符。
#在这里第一个字符和最后一个字符是一定要有的,也就是说至少是二字词,第二字符出现的话,加上首末就是三字词了,第三字符出现的话就是四字词了,对这四个字符,分别设为了子表达式,其他的字符不参与编码,就略去了。
#替换部分分解:\T{\1}对第一个找到的字符进行自定义替换,1为插入标志数字,\T{\2}2\T{\3}3对三字词以上词条进行自定义替换,并插入标志数字,如果字符不存在就只插入数字,\T{\4}4对最后一个字符进行同样的处理,这一个编码一定存在,\t插入间隔符,&重写查找的内容,也就是词条。
#这样一行就完成了编码与词条的分离。
(..).+123(..).+4\t(.*) \1\2\t\3
#这一行对二字词进行编码,特征是查找内容中23前面是
空白,只有首末即14前面有编码。(..).+这就是编码,(..)此为前ffice:smarttags" />两码,就把它设子表达式,(.*)是词条内容。
#替换项中:\1\2是把二字的前两码写上,然后插入间隔符\t,最后写入词条\3。
(.).+1(.).+23(..).+4\t(.*) \1\2\3\t\4
#此行对三字词进行替换,特征是3前面没编码,前二字取第一码(.),第三码取前二码,就是(..).+4中的(..),替换项是依次写入编码和词条。
(.).+1(.).+2(.).+3(.).+4\t(.*) \1\2\3\4\t\5
#此行对四字以上词条进行编码,原理同上,只是各取第一码。
fficeffice" />
在理解的过程中,一定要对每一个表达式和代码的意思都要搞清楚,因为五笔编码个性化的编码方式很多,每个人要实现的目的也不同,大家理解了,就可以自己试着编些变化型。
[ 本帖最后由 vu 于 2007-10-26 09:10 PM 编辑 ]