找回密码
 立即注册
搜索
查看: 4945|回复: 1
打印 上一主题 下一主题
收起左侧

[教程] 正则表达式于中文排版中的简单运用

[复制链接]
潇琊 该用户已被删除
跳转到指定楼层
楼主
发表于 2010-11-18 16:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在暗夜看到这帖子对排版很有帮助,所以转载过来,希望对大家有帮助。
本教程转载【暗夜仰望—泡泡】的帖子
原帖:http://www.ayyw.org/read.php?tid-40871.html



本教程主要说明,如何使用正则表达式在Em中对中文文本进行排版。

目录

1. 引言
2. 正则表达式的组成
   2.1 元字符
   2.2 重复
   2.3 字符转义
      2.4 集合
      2.5 分组
      2.6 后向引用
3. 正则的实际运用
      3.1 格式的整理
      3.2 内容的整理
4. 正则在脚本中的运用
      4.1 常用代码的含义
5. 小结


1. 引言

何为正则表达式?(以下简称正则)

  正则可以理解为高级搜索替换功能。传统搜索功能只能是输入什么就查找什么,必须完全匹配。正则表达式可以查找一些规定的格式,只要符合条件的内容都将被搜索到。

  PS:我所提到的正则主要用于文字版小说的修改。我所学习的正则均来自:正则表达式30分钟入门教程

  这篇教程写得非常好,语言很简练,也很好理解,但是就是太全,对于中文排版来说,很多是不需要的,而且他举得例子也没有关于中文排版的,我觉得对于一个新东西的学习,例子比较重要,可以让人更快的理解,所以,我根据自己使用正则的心得整理出这篇教程。

  大家都觉得正则很难,其实一点都不难,只是大家对计算机语言的一些误解罢了。正则对于我们来说,只是新,只要你肯学,几个小时就可以很熟练。
现在举一些例子,说明正则的用途。

  比如我们在处理文本时,经常会遇到这些信息: 发布时间 2010-6-7 本章字数:3533,每个章节都有,要删除很麻烦,用以往的复制查找,全部替换,无法做到全部清除,怎么办?一句一句删除吗?那太慢了,现在,我们就可以使用正则来删除,一步就搞定。在查找框输入 发布时间\s*\d{4}.+本章字数.+\d+,然后全部替换,就能把所有的这类信息删除。这里的正则只做例子使用,说明其用途,具体使用方法后面会解释。


2. 正则表达式的组成
   
    正则的组成:由多个元字符(也有叫通配符的)组成,按写者本身的需要组成一定的顺序。也可以和汉字及其他我们需要查找的符号连用,达到精确查找的目的。

    例如:(以下为举例,不需要理解)

    \d+

    \s*\w+\d{3}.+$

    电子书.+更新时间.+字数.+$

    \$手打\\\[小说\]

    【元字符】:用来替代某一类型的字符。


2.1 元字符
[size=4 ][size=4 ]元字符代码[size=4 ][size=4 ]元字符含义
[size=4 ][size=4 ]. 句号的半角形式[size=4 ][size=4 ]能替代除了换行符以外的任意字符
[size=4 ][size=4 ]\w  w为小写[size=4 ][size=4 ]能替代字母、数字、下划线及汉字
[size=4 ][size=4 ]\W  W为大写[size=4 ][size=4 ]与\w互补,即\w+\W=全部字符(不包括换行符),\W能替代除了字母、数字、下划线、汉字及换行符以外的字符
[size=4 ][size=4 ]\s  s为小写[size=4 ][size=4 ]能替代任意的空白符(文字小说中一般为半角及全角空格)
[size=4 ][size=4 ]\S  S为大写[size=4 ][size=4 ]与\s互补,能替代除了空白符、换行符以外的任意字符
[size=4 ][size=4 ]\d  d为小写[size=4 ][size=4 ]能替代数字
[size=4 ][size=4 ]\D  D为大写[size=4 ][size=4 ]与\d互补,替代除数字、换行符以外的任意字符
[size=4 ][size=4 ]\t  t为小写[size=4 ][size=4 ]制表符,也就是我们键盘上的Tab键,相当于输入一个大空格,长度等于8个半角空格
[size=4 ][size=4 ]\n  换行符[size=4 ][size=4 ]EM中为每行行末的蓝色“
[size=4 ][size=4 ]^[size=4 ][size=4 ]对应位置为一行的开始 在键盘上与数字6在同一键位
[size=4 ][size=4 ]$[size=4 ][size=4 ]对应位置为一行的末端 在键盘上与数字7在同一键位


下面配合例子说明用法:

  这里有个地方需要注意一下,中文的标点符号及其他特殊符号只能由.来替代。

  我的电话是:123456789

   用正则匹配就是:

  \w\w\w\w\w(5个汉字).(冒号)\d\d\d\d\d\d\d\d\d(9个数字)

  好长一串……这里就需要用到正则的另外一类元字符——重复。

2.2 重复

元字符代码元字符含义
*重复零次或更多次,意思就是可有可无,无数量限制
+重复一次或更多次,意思就是一定有,最少有一个
?重复零次或一次,意思就是可有可无,有的话最多只能有一个
{n}(n为自然数……)重复指定的n次,就是说有且只有n个
{n,}(n后为半角逗号)重复n次或更多次,就是说最少n个
{n,m}重复n到m次,就是说做少n个,最多m个

配合前面那个例子说明用法:

  我的电话是:123456789

  这句话用重复就可以写为:

  \w{5}.\d{9}

  查找被引号包围的句子,“不敢当,耿照见过代掌门。”表示为:

  “.*”

  “”与原文对应,.对应除了换行以外的所有字符,包括中文标点符号。*重复任意次,.*指的就是任意个字符。

  查找章节及其后四字的章节名称,第十章 勾心斗角。表示为:

  第.*章 \w{4}

  在不确定章节与名称之间有没有空格的情况下,可以写为:

  第.*章\s*\w{4}

  查找文中的1000以内的数字:

  \d{1,3}

  那如果我们要查找的内容包含元字符本身呢?

  比如:

  我的电话是:159********

  写成这样\w{5}.\d{3}*{8}肯定是错误的,表达式将运行出错。因为*在这正则里是重复的作用,{3}与*都是重复,连用两个是冲突的,那如何表达*本身呢?这 里就需要一个新规则——字符转义


2.3 字符转义

    因为我们在正则表达式里已经给“*”“[]”“\”这些符号下了定义,使用它们将达到特殊的效果,那如果我们要查找这些符号的本身呢?我们就需要使用字符转义了。

    字符转义的作用就是把正则中用到的元字符所替代的含义取消,直接输出本身。使用方法为:

    在你想输出的元字符前面加一个\,想查找文中的半角句号就是\.查找[]就是\[\],查找\本身就是\\。

    那刚才那句 我的电话是:159******** 就可以写成:

    \w{5}.\d{3}\*{8}


2.4 集合

接下来说下集合的使用,什么是集合?

  例如“[1234567890]”就代表任意数字,意思就是只要满足[]中的任意一个,也可以写成[0-9],搜索文章中的他她它,写为[他她它]。

  集合也有互补模式,格式为[^],比如[59]是查找数字5或9,[^59]就是查找除了数字5和9及换行符以外的任意字符。

  如果要查找第X章XXXX,章数与章名之间没有空格,如果表示成第.*章\w{4},就有可能出错,比如:XXX天下第一。XXX毫无章法乱七八糟的,XXXXXX,红字部分也符合表达式要求。这里我们就需要用到集合来精确匹配。第[一二三四五六七八九十两百零〇]{1,5}章\w{4},这样第和章之间只有中文数字可以匹配。

  再说下集合互补模式的使用。(其实我所说的互补模式,正规说法叫做“反义”,但是我觉得叫互补比较容易理解。)

  比如查找引号的错误使用,如下:

  他慌忙起身抱拳:“不敢当,耿照见过代掌门。“

  这句话的反引号使用错误了,我们要把它找出来,就可以使用“[^”]*“,意思是“后面跟着不是”的字符任意个,直到又一个“为止。

  他慌忙起身抱拳:“不敢当,耿照见过代掌门。“许缁衣名动东海,行事却没什麽架子,见他神态拘谨,微微一抿,轻抬柔荑:“七大派同气连枝,算来都是自己人,耿大人不必客气。来!都坐下说话罢,符姑娘也坐。”说著提起裙膝,袅娜落座。染红霞神情僵冷,木然坐在大师姊身畔。

  如果使用“[^”]*“所找到的为红字部分,因为正则默认是尽可能多的匹配,称为贪婪模式。为了避免这种情况,这里需要用到另外一个定义,叫懒惰模式,与贪婪模式对应,尽可能少的匹配。使用方法为,在重复元字符后面加个?,上面那个例子就可以写为“[^”]*?“,它所对应的就是我们所要找的“不敢当,耿照见过代掌门。“。

  另外还有一种形式与集合类似,但比集合的使用更为灵活,叫分枝条件。我把它理解为或,是并列的关系。

  分枝条件所使用的元字符为 | 一条竖线,使用方法为:

  他|它|她,效果与[他它她]一样,都是搜索他它她三个中的任意一个。把他理解为他或它或她就好懂了。

  分枝条件的其他用法将在后面配合其他功能一起讲解。


2.5 分组

  分组很简单,但是要解释起来还很麻烦。

  打个比方吧:

  我们要查找一个叠词“嘭嘭”,那我们就可以写成这样:嘭+或者嘭{2};那如果我们要查找这样的呢?

  欢迎欢迎,正则写为欢迎+,肯定是错误的,它只匹配欢迎迎迎这样的。这时候我们就要给欢迎加上个小括号,也就是分组。(欢迎)+或(欢迎){2},这样就对了。

分组配合分枝条件使用,妙用无穷~下面就说下用法。

  “的”后面跟名词,“地”后面跟动词,“得”后面跟形容词。这是基本常识,但是现在的网络文学很不注重这些。那一些精校文本就要改正这些错误。怎么实现呢?

  高兴的说,认真的写,兴奋的叫。这些的字的用法都是错的,搜索它们的正则就是(高兴|认真|兴奋)的[说写叫]。

  前面部分不能写成[高兴认真兴奋],写成这样,它的搜索范围只是单字,只对应这样的情况,比如:高的叫某某某,矮的叫某某某的红字部分。后面部分因为都是单字,所以没有这种顾虑。但是如果我们要查找的目标多了一个“端正的坐着”呢?

  表达式就要改为:(高兴|认真|兴奋)的(说|写|叫|坐着)。

  接下来说另外一个与分组有密切关系的用法——后向引用。



本帖最近评分记录:


隐藏评分记录清空我的评分动态 共 条评分   



回复 引用 评分 新鲜事
评分选定举报顶端

泡泡 离线
将为工作拼搏,预计潜水半年,不要想念我哈~~~

级别: 暗黑魔神



    [li]UID9432 [/li][li]精华 2 [/li][li]发帖259 [/li][li]铜币2210 枚 [/li][li]威望2914 点 [/li][li]贡献值6 点 [/li][li]习惯106 点 [/li][li]原创13 部 [/li][li]在线时间1291(时) [/li][li]注册时间2009-09-07 [/li][li]最后登录2010-11-14 [/li]

只看该作者   小中大   7楼 发表于: 06-12
2.6 后向引用

  前面只提到如何搜索,但是如果我们要将搜索到的内容进行修改就会出现一些问题。

  比如我们想要把第X章 XXXX,中间的那个半角空格替换为全角,其他地方保留不变,怎么办?

  搜索第[一二三四五六七八九十两百零〇]{1,5}章 (半角空格).+替换为第[一二三四五六七八九十两百零〇]{1,5}章 (全角空格).+吗?肯定是错误的。

  因为正则只在搜索框中起作用,替换框是你写什么就替换成什么。

  这里就需要使用分组的引伸用法——后向引用。

  搜索的正则改为:(第[一二三四五六七八九十两百零〇]{1,5}章) (.+)替换为\1 \2

  将除了半角空格以外的部分分成2组,这个括号的作用就是将括号中的内容命名。以每个括号的左括号为准,从左往右,第一个遇到的括号为1,第二个为2,依此类推。

  这里的\1就是第一个括号中的内容,\2就是第二个括号中的内容,\0则表示整个正则表达式本身。





3. 正则的实际运用

前面已经对与中文排版相关的正则进行了说明,下面结合排版实例进行说明。

一般来说,我们所有进行排版工作包括以下几种:

  1.格式的整理,细节方面有:段首空格的规范,段间空行的规范等。

  2.内容的整理,主要是对广告等无关信息的清理等。


3.1 格式的整理

首先来说下格式的整理:

  很多排版软件,以及众多Em排版脚本中都肯定有这个功能:规范段首。作用就是把每段前的空格是变成我们想要的形式,或2个全角,或不要空格等等。

  那这个功能到底是怎么实现的?这里用正则进行解释。比如我们现在要把所有段落开头的空格都去掉。

  那应该把^\s+全部替换为空。

  ^对应段首,只是个位置,专业一点的说法就是它匹配的内容长度为0。\s+就是空白符,至少一个空格。所以这个表达式就匹配所有的段首空格。

  那对应的,段末空格怎么去呢?\s+$全部替换为空。这句就不解释了。

  现在再进一步,如果想把每段开头都规范为两个全角空格的格式,怎么办?

  我们需要完成以下工作:

  段首本来有空格的,统一变成两个全角空格,没有空格的,统一加上了两个全角空格。也就是说无论段首有无空格,都替换为两个全角空格,具体如下:

  将^\s*替换为两个全角空格

  常见的格式整理还有规范段间空行,比如我想让文本变得紧凑,不要那些没内容的空白行,怎么办?

  删除^\s*\n就可以了。这个表达式所匹配的就是那些只有空格没有内容的行,或则单独一个回车的行。

  那如果想按照网络阅读格式,让两个章节间有一个空行,让阅读更舒服,怎么办?

  先用上面的正则把所有的空行都去掉,因为有的文本可能会有连着4~5行都是空行的情况。然后再把\n替换为\n\n就可以了。

  再进一步,改正那些随便分段的文本,比如一些贴文模式,它规定每行多少个字后面必须加一个回车,在电脑上看很舒服,但是到了手机上就不行了。

  有种比较简单的形式,它只是按字数换行,本来应该是段首的地方有两个全角空格,段间有一空行,非段间无空行,比如这样:

  那是在几年前的一个年底,我的女友去欧洲旅行,我自己除了上班外真的是
很无聊。我穿过拥挤的人群从商场中冲了出来,不太舒服的寒意让我觉得身体彷
彿还像孩子般的稚嫩,我想到了一个朋友,在这种天气中,他应该还躲在家里昏
睡。我的想法没错,敲了大概有十几分钟的门,他才不情愿的打开家门。

  “你真行!居然睡到现在!”我有些羡慕地看着他,他叫小天。

  小天不太好意思的笑笑,伸手指了指嘴,我无奈地掏出香烟,扔给他一支,
帮他点上火,我也顺便自己点了一支,走进他充满睡眠气息的卧房,歪坐在沙发
上。


  这种形式就可以将\n^([^ ])替换为\1,[^ ]方括号中为一个全角空格。整个解释起来就是如果换行符的下一行第一个字符不是全角空格,就把这个换行符去掉,使两行合并。

  另外一种形式就比较麻烦了,每行字数不一,段首无空格,段间无空行。比如:

那是在几年前的一个年底,我的女友去欧洲旅行,我自己除了上班外真的是
很无聊。我穿过拥挤的人群从商场中冲了出来,不太舒服的寒意让我觉得身体彷
彿还像孩子般的稚嫩,我想到了一个朋友,在这种天气中,他应该还躲在家里昏睡。我的想
法没错,敲了大概有十几分钟的门,他才不情愿的打开家门。
“你真行!居然睡到现在!”我有些羡慕地看着
他,他叫小天。
小天不太好意思的笑笑,伸手指了指嘴,我无奈地掏出香烟,扔给他一支,
帮他点上火,我也顺便自己点了一支,走进他充满睡眠气息的卧
房,歪坐在沙发上。


  这种情况只能以行末的标点来判定了。

  第一步:先把行末不是以标点结尾的行,与下一行合并。([^。!”:?—…])$\n(.)替换为\1\2,第二步,细节修正,”以这个结尾的夜不一定是段末,比如“称号”这就不是段末,但是不会合并行,所以需要把([^。!?…—]”)$\n(.)替换为\1\2。之后就可以进行其他细节排版,加段首空格,加空间空行等。


3.2 内容的整理

再说下内容的整理:

  个人觉得,内容的整理大体上包括:广告等无关信息的删除及错别字的修正。

  先说下广告的清理,广告可分为规则和不规则两类。

  规则型的,比如起点:起点中文网 www.*****.com 欢迎广大书友光临阅读,最新、最快、最火的连载作品尽在起点原创!

  删除的正则为:.*起点中文网.+连载作品.+$这类明显的就可以使用关键字加.+组合。

  飞库的:手机电子书·飞库网 更新时间:2010-3-12 13:26:06 本章字数:5483

  删除的正则为:.*飞库网.+更新时间.+\d+.+本章字数.+$关键字可以随便写,这类正则可以不需要那么严谨,不用逐字对应。

  不规则的,以奇书网为例。

  位于每段开头的[奇] *书* {网} @網@等以及位于文字当中的奇*書$网收集整理 (奇*书*网.整*理*提*供)

  段首广告删除正则:^\s*.[奇书网網].文中广告删除正则:\(?奇.*[书書].*[网網](收集整理|.*整.*理.*提.*供.*)

  这里解释一下,先说明段首那个正则。因为不确定其前面是否有空格,所以使用^\s*,然后是一个不确定的符号,使用.代替,接下来就是我们确定的,使用集合进行匹配。后一个正则,开头是\(?意思就是查找一个半角小括号,可有可无。然后就是需要精确匹配的文字,使用集合,不规则符号由于随意性太大,所以使用.*代替。然后使用分枝条件,以匹配不一样的后缀。

  如果想要彻底删除这种不规则的恶意广告,正则肯定不会这么简单,也不只一个,这里只做大致介绍,有兴趣的书友,可以自己尝试。

该说错别字的修正了:

  比如前面提到的“的”“地”字的修正。这个比较简单,只给出例子,你们自己思考吧。

  (这样|这里|哪里|那里|那样)地(人|话)替换为\1的\2。能看懂这次替换的结果是什么就过关了~

  再举一个例子:像与象的修正。头象 画象 象……一样这些用法是错误的。

  把(头|画|肖)象替换为\1像象(.+一样)替换为像\1

4. 正则在脚本中的运用

  这一小节主要是想说明如何自己修改脚本,以及脚本中常用代码含义。

  使用Em随便打开一个现有的脚本,或者使用编辑脚本功能。都能看到脚本背后的组成,大致情况如下:


  总体来说90%的脚本语句,使用的都是这一句document.seletion.Replace("要查找的","替换成",使用规则)。这个和我们平常使用的搜索替换功能是一样的。作用就是将后面那个引号中的内容替换成前面那个引号中的内容,是否使用正则等规则,在第2个逗号以后规定。


4.1 常用代码的含义

  在Em脚本中,中文排版方面我们所需要的代码前缀都是一样的document.selection。配合不同的后缀,功能强大。

  selection的后缀很多,有几十种,但中文排版中常用的就以下几种:
后缀名称后缀含义使用方法
Replace替换文中一个字符串。document.selection.Replace(要替换的,替换为,使用何种规则)
Find搜索指定字符串。document.selection.Find(要搜索的,使用何种规则)
StartOfDocument将光标移动到文档的开始。document.selection.StartOfDocument(规则)
EndOfDocument将光标移动到文档的末尾。document.selection.EndOfDocument(规则)
StartOfLine将光标移动到该行的行首。document.selection.StartOfLine(规则)
EndOfLine将光标移动到该行的行末。document.selection.EndOfLine(规则)
LineUp将光标上移n行。document.selection.LineUp(规则,n)
LineDown将光标下移n行。document.selection.LineDown(规则,n)
Delete删除光标右侧n个字符。document.selection.Delete(n)


  下面来说下各个规则的用法,为了CHM版的美观,所以规则另外说了:

  Replace和Find规则是一样的:
规则名称规则含义
eeFindNext这个就是我们平常用的查找下一个。
eeFindReplaceRegExp使用正则,相当于在查找框使用正则那里打上勾。不能与eeFindReplaceEscSeq一起使用。
eeFindReplaceEscSeq使用转义,相当于在查找框使用转义符那里打上勾。不能与eeFindReplaceRegExp一起使用。
eeReplaceAll这个就是我们平常用的替换全部。


  以上规则除正则与转义冲突以外,其他都可以混用,混用时,两个规则之间用|连接。这里配合排版实例说明用法。比如我们现在要对文本进行简单的段落整理。将文本整理为段首两全角空格,段间无空行的形式。方法如下:

  document.selection.Replace("^\\s*(.)","  \\1",eeFindNext | eeReplaceAll | eeFindReplaceRegExp);
  document.selection.Replace("^\\s\n","",eeFindNext | eeReplaceAll | eeFindReplaceRegExp);
  特别注意,除了换行符\n以外,其他所有正则的\都要写成\\的形式。个人建议,\n在脚本中也写成\\n的形式,这样肯定不会错。


  大家肯定会发现,真正的脚本中,它的规则不是这么写的,规则处写的都是nFlags,那是因为他在脚本开头给eeFindNext | eeReplaceAll | eeFindReplaceRegExp下了定义,让nFlags代替这3个共用情况,这3个规则一起就是使用正则全部替换,最为常用,定义后方便脚本的书写。

  StartOfDocument EndOfDocument StartOfLine EndOfLine这四个规则也是一样的,但是比较简单,只有turefalse两种,使用ture的效果就是,移动光标,同时选中光标当前位置与光标目的地之间的内容。false效果就是不选中内容,只移动。实例如下:

  当你搜索某个东西的时候,你肯定会手动把光标移动到文本开头,不然可能会漏掉,脚本也一样,如果你不给他下命令让光标回文首,它就只会从光标目前位置开始执行代码。所以,部分脚本功能的可能会有这么一句代码:document.seletion.StartOfDocument(false);,将光标移至文首,但是不选中内容。至于需要选中内容的情况较少,就不举例了。

  LineUp LineDown,规则同上,只是多了个数字,想移动几行就填几。

  至于Delete,这个比较好理解了,你要删几个字就填几。配合几个移动光标的功能,可以对大量信息的进行删除。




5. 小结

  教程到这里就结束了,个人觉得正则不难,只要多练手就能很快熟练,只看不动,肯定觉得困难。而且TXT文本,这种东西到处都是,随便搞几个回来,自己摸索着玩,很快就可以玩出些感觉的。

  对于想自己写脚本的书友,可以看这里:【教程】如何整理自己需要的脚本,这帖虽然很业余,没什么专业的内容,但是可以省去你一些时间。

  本文是初版,若有需要,会持续更新。若发现文中有问题,请及时提出,跟帖也行,发站内短信也可以。有疑问也可以提出来,我尽量解答;更欢迎高手指点。




  唯一的区别就是:在脚本中,所用需要使用\的代码都变成两个\,比如查找数字,原本为\d,在脚本中应写为\\d,个人理解为,脚本中的正则比我们直接在Em搜索功能中使用正则需要多通过一次的编译。

  脚本其实就是把很多步的排版操作按照一定顺序集合到了一起,通过代码,使使用者只需要点击一次就自动运行大量语句,实现复杂排版轻松实现的目的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
筷子 该用户已被删除
沙发
发表于 2010-12-16 12:03 | 只看该作者
说实话,有点令人抓狂。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋| ( Q群816270601 )

GMT+8, 2024-11-16 12:55 , Processed in 0.362908 second(s), 18 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表