舍得英语魔法学苑

 找回密码
 注册
查看: 545|回复: 9

[UX] 正则表达式处理复杂文本思路[图文]

  [复制链接]
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

    qixiaobin0715 发表于 2018-9-30 14:03:17 | 显示全部楼层 |阅读模式
    本帖最后由 qixiaobin0715 于 2018-9-30 14:08 编辑


        我第一次接触正则表达式还是从舍得的帖子“正则表达式实用教程”开始的。没有学习正则之前,制作课程想想真是太累了。自从开始认识正则,边学边做挺有成就感的。从简单的,再到复杂的,一路下来制作了不少课程,有给自己用的,有给孩子用的,还有给朋友用的。通过这几年的学习,也积攒了不少心得体会,但一直没有进行总结。
        现在虽然学苑里没以前热闹了,我发现关于正则表达式的帖子还是有不少人关注的,以前这方面的帖子时不时就被翻出来,除了舍得的帖子外,最近又看到“优仕新概念源文本处理之短语篇(正则表达式教程)”(2013年)成为热帖,以前刚接触正则时也曾看过,受益匪浅,当时是以初学者的态度学习的。现在又重新浏览,虽然是时过境迁,还是有新的收获。因为现在自己也有些许心得,所以在浏览过程中主要是思考他的处理文本时的思路,思考如果是换作自己如何做。
        我以前制作课程后,处理的文本都没有保留,手头又没有典型的文本可用,而xsqxsy兄提供的原始文本和处理后的文本比较全,更具代表性,所以就想以xsqxsy兄的源文件为例对应用正则表达式处理文本的思路、方法、技巧进行总结,分享给大家,同时使自己也能得到提高。没有事先征得xsqxsy兄的同意而利用其资料,恳请不要怪罪。
        本想将自己的体会附在以上提到的两个帖子中一个,最终还是决定开个新帖:一则舍得的帖子是引导大家去学习正则的,提炼出拿来就能用的条目,所谓“实用”的由来;其次xsqxsy兄的帖子也花了不少心思,构思严谨实用,但其只是针对特定文本处理的过程做一说明。
        本帖重点在于对源文本处理的思路进行探讨,也即是拿到想要制作课程的资源,如何对其文本部分进行分析,如何处理文本才能达到自己想要的格式。由于是以xsqxsy兄的源文件作为例子,可能叙述过程中,要与帖子中的部分步骤做对比,本人绝无意与人争一高下,而是为了更好地说明自己的思路,敬请谅解。
        开场白有点太长了哈,但是有些情况还是要先说清楚的好,这也是激励自己不要在后面搞的虎头蛇尾,惹人议论。后面的内容可都是干货了,先占个位置。节后一期一期的慢慢道来。
    xsqxsy兄课程链接:
  • TA的每日心情
    擦汗
    2018-10-25 19:02
  • 签到天数: 404 天

    [LV.9]以坛为家II

    wsqiyijiang 发表于 2018-10-7 10:02:10 | 显示全部楼层
    厉害,正则的运用真的可以省去好多麻烦
  • TA的每日心情
    擦汗
    2018-10-25 19:02
  • 签到天数: 404 天

    [LV.9]以坛为家II

    wsqiyijiang 发表于 2018-10-7 10:02:30 | 显示全部楼层
    厉害,正则的运用真的可以省去好多麻烦
    [发帖际遇]: 一个袋子砸在了 wsqiyijiang 头上,wsqiyijiang 赚了 2 颗 魔晶石. 幸运榜 / 衰神榜
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

     楼主| qixiaobin0715 发表于 2018-10-9 12:33:56 | 显示全部楼层
          当你拿到一份资料后如何将其最终制作成满意的课程呢?下面就正式探讨这一问题。
          现在先理一理思路,列一个大概的提纲,省得以后东一榔头西一棒子的。可能以后还会做少许调整:
          一、        如何对全部资料进行分析?包括文本、音频、图片、影像等。
          二、        如何对文本资料进行分析。
          三、        文本处理的大致思路。
          四、        文本处理用到几种不容易理解或容易理解错误的正则表达式的解析。
          五、        用实例说明文本处理的全过程。


          首先对第一点进行说明:
          本文主要是谈对文本处理的体会,但是其他资料也必须建立与文本的联系,才能制作内容丰富的课程,所以对这一部分也要进行简单的说明。
          处理文本前首先要看看手中的其他资料与文本之间是如何关联的:

          1.        文本内容如果与图片音频影像没有直接联系,就要想办法让其发生联系。
          2.        对于相对独立的图片音频影像处理起来较为容易,可直接提取文件名(用cmd中的DIR命令或批处理bat)并按文本顺序排列,然后插入文本。
          3.        如果图片音频影像不是相对独立的话,处理起来就麻烦的多了。比如图片是PDF文件并连在一起,音频影像是一段一段的,就需要用专用软件切割。图片切割推荐用snagit,音频影像建议用Aboboo。
          4.        如果文本内容中有与图片音频影像相联系的内容,处理文本时一定小心应对,千万不能丢失这些联系。

    [发帖际遇]: qixiaobin0715 乐于助人,奖励 9 分 学分. 幸运榜 / 衰神榜
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

     楼主| qixiaobin0715 发表于 2018-10-11 09:38:45 | 显示全部楼层

    二、对文本资料进行分析
      文本资料是制作课程的核心。文本资料的分析是极其重要的环节,对后面的文本处理、课程模型的构思起到非常关键的作用。分析文本时主要关注以下内容:
      1. 文本资料格式是什么,是多个还是单个?文本资料无论是什么格式,处理前都要转换为txt文件。单个文本文件就不用说了,若是多个文本文件(比如几十上百甚至更多)可采用抽样分析,一般不应低于5%(文件太多时不少于10个)。这样做可减少以偏概全的错误。
      2. 其次要了解文本的基本结构,对每一部分进行分类。比如这部分是第一章的内容,那是第三章;具体到每一章中,哪里是“标题行”,哪里是“对话”,哪里是“练习题”,哪些是对课程无用的标记(索引、页码、页眉页脚等),都要搞清楚。
      3. 对第2点分析完后,还要进一步了解每一部分内部的结构,各部分之间的关系如何,哪些行需要合并,哪些内容需要分隔。
      下面就以xsqxsy兄提供的一个文本文件中的第一课的文本来说明如何分析文本。
      为了便于说明我们作如下规定:
      每一课就叫:                                     章(或课)
      每段相连单词或相连短语或相连对话等分别就叫:     单元
      每个单词或短语等的内容:                         节
      文本部分截图如下。图1、2、3、4是按顺序截取的典型文本样本,可参照“优仕新概念源文本处理之 短语篇”下载文本资料,为了使大家便于对照学习,截图包括了行号(最左边)。应如此这般的分析文本特征:
      1. 红圈标识代表章,蓝方标识为单元,黄圆尖标识为节,箭线指向分界位置,钢笔圈起来的部分为特殊标记。
      2. 图1红圈A到图4红圈A的范围内也即第1~460行是第一课(章)的内容。课的标记为@L+数字。L——lesson。图4红圈B代表新一课的起点。
      3. 图1蓝方a到图2蓝方a(4~145行)为一个单元单词的内容。单元的标记为P000000dc,dc——单词,每个单元有多个标记。
      4. 图2蓝方b到图3蓝方b(146~198行)为一个单元短语的内容。单元的标记为P000000dy,dy——短语。以此类推。
      5. 图1黄圆尖1为单元a中的一节内容,即高亮部分为单词go的内容。
      6. 第1、2、3节中,红色短箭头表示在一行内不同内容的分界线,如第148行第一个箭头是短语音频代码taf0034与英语短语的分界,第二个箭头是短语(或句子)与中文含义的分界(三个空格)。处理文本时这些位置需用制表符分隔。
      7. 黄色箭头英汉分行的分界,注意特征:行首三个空格。处理文本时应合并为一行且用制表符隔开。
      8. 白色箭头为两行英文,本来就应当合并在一行中,特征与上一条相同。处理文本时直接合并为一行,不需要制表符分隔。源文本中未分行,个别地方有此情况出现,为减少截图,我自己修改的。
      9. 红色钢笔圈中的部分也即~S,为音频代码标记,它们后面的字母加数字部分(不包括~S)为音频代码,也即是音频资料中音频的文件名。如第453行音频代码为C2083002,~S中的S为sound的第一个字母。
      10. 叉号表示文本不需要的部分,特征为紧靠“课”或“节”的后面,中间没有空白行相隔,会对处理文本带来麻烦。一种是以“& ~C~P000000choose”开头(可能是程序需选择单词、短语、句型、对话、短文等“单元”;另一种是以“~N”(可能number开头字母)开头,以dn.、up.或bk.结尾,可能是程序中向上、向下、返回指令。这些内容是处理文本时首先要去除的。









      以上就是分析文本的一个思路,处理文本时,每进行一步还是要对每次处理完的文本进行分析,以免出错,影响后续的处理。自己分析文本时,可不做标记,但应做到心中有数。我是为了讲述方便而为之。

    本帖子中包含更多资源

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

    x
    [发帖际遇]: 一个袋子砸在了 qixiaobin0715 头上,qixiaobin0715 赚了 1 颗 魔晶石. 幸运榜 / 衰神榜
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

     楼主| qixiaobin0715 发表于 2018-10-16 11:11:47 | 显示全部楼层
    三、文本处理的大致思路
       
      前面已经就文本的分析进行了探讨,得到了文本的基本结构。
      处理文本前还要了解UX课程与最终处理的文本有何关系:
      
      1.        最终处理的文本的每一“行”包含了与之对应的UX课程一个“页面”几乎所有的信息,也即是每一行对应一个页面;
      2.        信息可以是显性的,也可能是隐性的。如上节所说的音频代码是显性的,如果你有以单词命名的音频库图片库,单词栏就可以作为隐性信息,既可以作为页面中的文本用,也可作为提取音频或者图片的代码;
      3.        如果想用舍得的转换精灵制作课程的话,最终处理好的文本就必须采取固定格式,文本中不同信息都必须用制表符隔开。
      4.        用上节中的图片来说,UX主窗体(中间部分)的内容与例子中的每一节(高亮部分)一一对应;
      5.        UX课程如果要划分章节的话,也要在每行中体现章节信息,对应页面中的侧栏和顶栏。
       
      详细对应关系可参照xsqxsy兄的另一个帖子http://emagic.org.cn/thread-24581-1-1.html中的内容。里面有非常详尽的说明。
       
      综上所述处理文本的目的就是要把需要部分的每节的内容分别合并为一行,不同的信息用制表符隔开。
      xsqxsy兄处理文本的思路是先删除单词、句型、对话、短文、其他无用信息等内容,保留短语部分,再进行处理。其好处是可排除干扰,集中精力处理“有用”信息。这也是一种思路,其中还用到了“.”匹配换行符的功能。
      这里我提供另一种思路。除了短语内容之外,单词、句型、对话、短文等可以留作以后制作其他课程用,这部分先保留,经过分析,其结构与短语部分有许多相同之处,处理短语的时候这部分也能得到相应的处理,以后用这些材料制作课程时可减少不少文本处理工作量。“.”匹配换行符是正则表达式中的扩展功能,一般默认处于关闭状态,正则表达式通常都是在行内起作用,这是有它的道理的。开启扩展功能,增加了表达式匹配的复杂性,这时一定要头脑清醒,否则会造成误配,理解起来也有难度,不适合初学者;对于超大内容的文本即使匹配无误,也会造成匹配效率低,速度慢的现象。xsqxsy兄有几处替换需进行多次,究其原因是由于使用了跨行匹配,不知道要替换几次,容易造成困惑,建议采用行内匹配。实际上不开启“.”扩展功能也能进行跨行匹配,但也要尽量避免使用,具体跨行匹配和行内匹配的区别下节具体说明。
      处理文本时,可先去掉真正无用且对处理文本有干扰的信息,比如图中打叉部分。随后应把焦点放在短语部分,兼顾其他进行处理。当进行到短语部分的每一节分别合并为一行时,这时应当把文本进行备份,留作制作其他课程用。这时短语部分行首就有了特殊标志,与其他部分就能区分开来,短语部分就能提取出来。将每一课的内容分别合并为一行,以便进一步处理,这就是我所说的尽可能进行行内处理。将每个短语的内容前加上章节号也即是“第**课”并分行。每行行首加词条序号,首行加上列标题。就此文本处理就告一段落。此处只是大致描述文本处理过程,可能不太好理解,看完后面具体图文处理过程就明白了。
       
    [发帖际遇]: 一个袋子砸在了 qixiaobin0715 头上,qixiaobin0715 赚了 5 颗 魔晶石. 幸运榜 / 衰神榜
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

     楼主| qixiaobin0715 发表于 2018-10-19 15:31:03 | 显示全部楼层

      四、文本处理用到几种不容易理解或容易理解错误的正则表达式的解析
      
      从这里开始一直到结束的内容,会一直以正则表达式为核心,所以一定要对正则表达式有一定的基础才能看懂。这个帖子主要是讲文本处理的,不是讲解正则表达式的,对正则不是太了解的,应当先去认真学习后再看以下内容。正则表达式的各种表达形式单个讲起来很简单,但是组合起来相当复杂,即使是多年的老手也会出错。我在文本处理过程中使用正则表达式时,力求简单明了,让大家更容易理解。
      
      1. .*和.*?
      
      正则表达式中经常碰到“.?”、“.*”、“.+”和“.??”、“.*?”、“.+?”及其他变种,你知道它们之间有何区别吗?下面先以.*和.*?进行辨析:
      许多人在学习正则表达式时,对上面两种式子没有理解透彻。
      常见正则表达式元字符分为以下几个大类:
      a.字符表示法;b.字符组及相关结构;c.锚点及其他“零长度断言”;d.注释和模式修饰词;e.分组、捕获、条件判断和控制。
      “.”可以归属为b类,它是几乎能匹配任何字符的元字符,其后无量词时,表示匹配单个字符。量词属于e的“控制”类别,主要是对某一字符、字符组或表达式的数量进行限定的。量词分为匹配优先、忽略优先和占有优先量词三类,前两类较为常用。?、*、+是属于匹配优先量词的,也叫贪婪量词,匹配尽可能多的内容;??、*?、+?属于忽略优先量词,也叫懒惰量词,匹配尽可能少的内容,只需要满足下限,匹配就能成功。下面就以具体例子来说明.*和.*?的区别。*表示它前面的元素可以有任意多,也可以没有。
      先说两者之间的相同点,都表示可以匹配任意多的字符或者如果不匹配任何字符也可以。其区别也是非常明显:
      .*所谓表示匹配优先(贪婪),是指当轮到.*匹配时,会从当前位置向后只要能匹配就尽可能多的进行匹配,直到不能匹配为止,才会停下来。若整个表达式没有结束,其后面还有其它元素或子表达式需要匹配且不能匹配成功,它就会把已经匹配字符中从最后一个开始逐个交还给其它元素或子表达式匹配,直到其后面的元素或子表达式匹配成功为止。
      图5给出了其匹配情况(图中显示的是文本中第一行的内容,在菜单“查看”中选中“按窗口换行”,便于观察第一行的整个内容)。正则表达式为^.*###,匹配文本的过程为:^表示锚点,属于c类,不匹配任何字符,只是说明整个正则表达式匹配起点为行首;接着用.*匹配文本,由于是匹配优先,.能匹配任何字符(除换行符外),所以从行首的第一个字符一直匹配到行尾都符合要求;再匹配###,由于前面已经匹配到了行尾,###不能匹配成功,就要首先交还最后一个字符“。”,还是不能匹配成功,再交还下一个字符“鞋”进行匹配,还是不能匹配,继续交还。如此反复直到退回到图中两个红色箭头之间的###为止,整个表达式匹配成功。匹配过程结束,匹配结果就是高亮部分。文本中间的多个###被.*优先匹配,如黑箭头所示,表达式中的###只是匹配了文本中最后一个###。
      

      
      而对于忽略优先的表达式.*?匹配过程与上述过程正相反。当轮到它进行匹配某个字符时就会对后面的“家伙”说,我先歇歇你来上,后面的也匹配不上时它才站出来匹配这个字符。然后继续下一个字符,直到整个表达式匹配完成。
      图6给出了其匹配情况。正则表达式为^.*?###,匹配文本的过程为:从行首第一个红色箭头开始先用.*?匹配@,由于是忽略优先,就让给后面的###先匹配,但没有匹配成功,回过来.*?再匹配@,成功;接着开始匹配第二个字符L,还是让###先匹配,失败后.*?匹配成功;如此反复直到匹配到第二个红色箭头,整个表达式匹配成功,匹配过程结束,匹配结果就是图中高亮部分。
      
      
      如果像图5那样的文本,行首是###时,.*?###匹配又是如何进行呢?首先.*?匹配第一个#,但由于是忽略优先表达式,所以先忽略匹配,由后面的###匹配,结果成功,整个表达式匹配结束。匹配结果就是行首的三个#,因为.*?(.*也是)不匹配任何字符,也算匹配成功。匹配结果如图7所示:
      
      
      总之用一句话来概括就是:匹配优先的正则表达式尽可能多的匹配文本中的字符直到整个表达式匹配完成,而忽略优先的尽可能少的匹配直到整个表达式匹配成功。

    本帖子中包含更多资源

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

    x
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

     楼主| qixiaobin0715 发表于 2018-10-25 12:10:56 | 显示全部楼层
    本帖最后由 qixiaobin0715 于 2018-10-25 12:24 编辑

    第四部分(续1)
    2.排除型字符组。
      其形式为[^…]。内部列出的是不希望匹配的字符。你可以把它看作普通字符组,里面包含的是除了“排除型字符组中所有字符”以外的字符,它仍然要匹配字符,可以理解为“匹配未列出字符的字符组”。
    把排除型字符组拿出来辨析是因为有一个不易被人察觉的情况,它能够匹配换行符。当打开“点号匹配换行符”扩展功能时,排除型字符组能够匹配换行符,所以在扩展功能打开时要特别小心,否则可能产生误配情况。还是用例子说明,在EmEditor中打开扩展功能,在文本中搜索两个“@”字符之间的文本:要求第一个@在行首,第二个@可以在任意位置(与第一个@可不在同一行)。用正则表达式 “^@[^@]*@”搜索。结果如图8所示:



    ^@表示第一个@位于行首,[^@]*表示匹配尽可能多的不是@的字符。整个表达式匹配的是“第一个字符是位于行首的@,最后一个字符是任意位置的@,中间所有字符不能存在@”的文本。高亮部分就是表达式匹配的内容,[^@]*匹配了除头尾的@外包括“换行符”在内的所有字符。
      实际上在EmEditor中使用排除型字符组不开启扩展功能时有一个bug,但一般不会出问题,这里就不再讨论了。在“查找”对话框中试一试这两个表达式“^[^a-z]+\n~”、“^[^a-z]+~”,用“查找全部”看看有什么不同,再多次点击“查找下一个”按钮仔细观察。不要忘了排除型字符组可匹配换行符。




    本帖子中包含更多资源

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

    x
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

     楼主| qixiaobin0715 发表于 2018-10-29 13:50:53 | 显示全部楼层
    本帖最后由 qixiaobin0715 于 2018-10-29 13:59 编辑

    第四部分(续2)
      3. 锚点及其他“零长度断言”。我们只讲下面六种:^、$、(?=…)、(?!…)、(?<=…)、(?<!…)。我们在实际匹配时可能用到,这里先普及一下这方面的知识。

      我们一般把^和$叫做锚点,其它四种叫零长度断言或者环视,其本质上是相近的。先说锚点,它们分别表示行/字符串的起始和结束位置,并不会匹配任何文本。如图8中所示,蓝箭头、绿箭头分别指向前三行^、$表示的位置,^表示行首第一个字符前的地方,$表示行尾最后一个字符后面,换行符前的地方。
      和锚点一样“环视”也是不匹配任何字符,也是只表示某一个位置,只不过它可以表示任意地方的位置,比单纯的锚点要复杂的多,但是更加通用。表2-2是《精通正则表达式》一书中的截图,简略说明了四种环视的用法。实际上表中的匹配一词应加上引号,因为实际并未最终匹配。

                                


      还是用具体例子来说明,如图8所示,要单独匹配第12行而不匹配第13、15行的单词train,而且要求它前后的字符都不能匹配。可以用表达式“train(?=   )”匹配,注意等号后面是三个空格;表达式还可以用“(?<!the )train”匹配,the后有一个空格。如果要匹配13、15行的train而不匹配12行的train表达式如何写呢?“train(?= ) ”行吗(等号后一个空格)?这样三个train都会被匹配,如果文本只有这三行有train,表达式可以这样写“train(?!   )”,等号后三个空格;或者写作“(?<=the )train”,the后有一个空格。
      这里按顺序解释以上四个表达式的意义。可以这样理解“环视”:我站在原位不动,向四周看看有什么情况,是否符合我的要求,图8中train前后的箭线指向代表“原位”。为了便于理解下面的说明采用通俗的语言表达,可能不是正则表达式引擎的实际匹配过程。匹配时先找到所有的单词train,然后用环视进行判断。对于第一种表达式“train(?=   )”来说,站在单词最后一个字母n的后面,由于是肯定顺序环视,这时就要向右看看是否是三个空格,是的话,train匹配成功,否则train匹配失败,但三个空格只是作为判断能否匹配的条件,而不参与最终匹配;对于第二种表达式 “(?<!the )train”,由于是否定逆序环视,就要站在train第一个字母t的前面向左看看,是否是“the+空格”,不是的话匹配成功,是的话放弃匹配;对于“train(?!   )”,由于属于否定顺序环视,站在n的后面向右看看,如果不是三个空格匹配成功,否则放弃匹配;对于 “(?<=the )train”,肯定逆序环视,站在t前向左看看,如果是“the+空格”匹配成功,否则放弃匹配。重要的话要多说一遍:以上所有匹配的字符都是train,而the和空格均未最终匹配,大家可以实际操作一下,多多体会。
      还有一点需要说明的是,在许多程序中逆序环视只能“匹配”固定长度的文本或子表达式长度受限,而在EmEditor中,逆序环视只能“匹配”固定长度的文本。比如(?<!cats?)是非法表达式,cats?换成cats*或cats+也不成,但如果正则表达式引擎换为Onigmo,(?<!cats|cat)是合法的。而顺序环视一般不受限。


    本帖子中包含更多资源

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

    x
  • TA的每日心情
    擦汗
    5 天前
  • 签到天数: 1679 天

    [LV.Master]伴坛终老

     楼主| qixiaobin0715 发表于 2018-11-1 14:18:48 | 显示全部楼层
    本帖最后由 qixiaobin0715 于 2018-11-1 14:27 编辑

      第四部分(续3)
      4.跨行匹配、行内匹配及其他。
      先说说xsqxsy兄的“优仕新概念源文本处理之 短语篇(正则表达式教程)”中的一个疑问,在第7条的正则表达式中。
     
     

      只要打开了“.号匹配换行符”的扩展功能,我所知道的能匹配换行符的元字符就有三种:点号;排除型字符组;\s。
      \s 可以匹配任一空白字符,包括空格、制表符、换页符、回车符和水平制表符。等同于字符组[ \f\n\r\t\v]。所以第7条中\s+不仅匹配了空格也匹配了换行符,替换时由于\s没有在括号内,没有被捕获,所以替换后就不存在了。
      打开了扩展功能有可能对匹配带来意想不到结果,所以我前面说处理文本时尽量还是不要使用跨行匹配的方法。
      在打开扩展功能后,以上所述的三种情况都可以实现跨行匹配。关闭扩展功能也能跨行匹配,只不过跨行有所限制罢了,但也会出现小的问题。下面用例子说明关闭扩展功能后跨行匹配的情况。
      图9是我从xsqxsy兄提供的源文件中选取的一段文字,这样说明起来比较方便一些。我想把第10~16行的英语文本合并为一行。按照xsqxsy兄的方法(唯一区别这里未打开扩展功能),匹配用正则表达式^([a-z0-9[:punct:] ]+)\n([a-z]),替换用\1\2,也就是去除表达式中间的换行符达到合并的目的。经过分析,要合并的文本是由下面四种字符组成的:26个字母,数字,标点,空格。每一行可用第一个括号中的子表达式匹配,接着是换行\n,再下面是下一行的第一个字符,26个字母组成,由第二个括号中的字符组匹配。可用“查找”进行验证,点击查找全部,结果却与想达到的目标不一致,图中高亮部分就是表达式匹配的结果,原本要匹配六个换行符只匹配了三个。
      
      
      
      这是什么原因造成的呢?让我们先看看匹配过程:为了简化起见,这里把对前9行匹配失败的过程略过。用^([a-z0-9[:punct:] ]+)从第10行进行匹配,从行首一直到换行符前的g都得到匹配,\n匹配换行符,第10行匹配完成,接着用最后一个子表达式([a-z])匹配第11行行首的h成功,[a-z]后面无量词(?、*、+)只匹配一个字符,这样整个表达式完成一次匹配。下面还有文本,还会继续从第11行没有得到匹配的第1个字符,也即是h后面的e开始,寻找是否还有符合条件的匹配。由于表达式最前面是^,要求每次完整的匹配都从行首开始,而第11行的行首已经得到匹配,所以第二次匹配只能从第12行行首开始。依此类推,最终只能找到3个匹配。
      从上面匹配过程可以看出未得到想达到的匹配,是由于设定了每次匹配都必须从行首开始,那么去掉行首锚点^是否可以呢,你们自己可以去试试。这里可以给大家说,肯定可行,但是不好理解。你知道第二次匹配的文本是什么吗?是从第11行第二个字符e至第12行第一个字符h之间的文本。实际上我们可以从每行的行尾和下一行的行首做文章,这样思路就非常清晰。先看行尾,可分为以下几种组合:字母或数字+换行符;字母或数字+空格+换行符;字母或数字+标点+换行符;字母或数字+标点+空格+换行符。分析其规律就是字母和换行符之间空格、标点可以有,也可以没有,字母取一个,表达式不就出来了吗:[a-z0-9][\s[:punct:]]*\n,注意[:punct:]表示标点符号。行首就简单了,第一个字符都是字母或数字,表达式为[a-z0-9],综合起来总的匹配表达式为:([a-z0-9][ [:punct:]]*)\n([a-z0-9]),替换为:\1 \2,中间有一个空格,主要是考虑行尾为单词结尾,下一行以单词开头,替换后由于去掉了换行符,两个单词之间要用空格隔开。这样就不会出现一个正则表达式需多次替换的情况。
      下面列出几个可能用到的字符集合先让大家混个脸熟,处理文本时不再详述,自己可先查看有关资料学习:
      \w:在有些程序中等价[a-z0-9_](不分大小写),但在EmEditor中使用Roost.Regex引擎也包含中文字符。
      \s:空白字符集合。相对应\S是非空白字符。
      [:punct:]:标点符号集合。必须用在字符组中,如[[:punct:]]标点符号、[a-z[:punct:]]英文字母或标点。
      [^\x00-\xff]:中文及标点(可以这样理解,不确切,具体查有关资料)。
      [一-龥]:纯汉字,不包括标点和其他。

    本帖子中包含更多资源

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

    x
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    小黑屋|手机版|Archiver|官方微博|官方QQ群|舍得英语魔法学苑 ( 冀ICP备11024081号-1 )

    GMT+8, 2018-11-14 00:07 , Processed in 0.084570 second(s), 24 queries .

    Powered by Discuz! X3.2

    © 2001-2013 Comsenz Inc.

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