浅谈学习正则表达式的重要性

2019-01-08 11:05:45 浏览数 (1)

浅谈学习正则表达式的重要性

2017-08-10 by Liuqingwen | Tags: Hexo Web | Hits

一、问题

使用 Hexo 搭建博客确实简单又强大,简单在于构建和发布过程,强大在于它的扩展性。关于 Hexo 博客插件功能有兴趣的朋友可以参考我之前的一篇文章:分享几个实用的 HEXO 博客功能插件 ,但是有时候这些功能比较官方,我们还是需要自己动手 DIY 一下才能更好的适应自己的网页。我现在使用的博客 RSS 订阅功能这个插件( hexo-generator-feed )就不太适合我自己的博客行情

问题是这样的,因为我使用了图片懒加载的功能,导致生成的 RSS.xml 文件包含的图片部分是真实地址,部分是预加载图片的地址而不是真实源图片地址:

代码语言:javascript复制
<p><img src="http://url/to/imgloader.gif" data-echo="real-image.jpg"></p>
<p><img src="real-image.jpg"></p>
<p><img src="http://url/to/real-image.jpg"></p>

这个时候就需要自己动手稍微 Hack 一下插件的源码了,对整篇的文字进行查找替换就需要正则表达式派上用场了。

二、解决方法

对于 JavaScript 编程我是门外汉,不过好在正则表达式在不同语言之间是通用的,至少大部分场景是这样,那么对于会 Java 的我来说对源码简单修改一下足够了。关于正则表达式这里有一篇文章总结的比较好,刚好介绍了我需要使用的知识点:正则表达式中的不匹配,下面引用的是文章的正则表达式定义表格:

表达式

定义

表达式

定义

表达式

定义

表达式

定义

表达式

定义

abc

a或b或c

.

任意单个字符

a?

零个或一个a

^abc

任意不是abc的字符

s

空格

a*

零个或多个a

a-z

a-z的任意字符

S

非空格

a

一个或多个a

a-zA-Z

a-z或A-Z

d

任意数字

a{n}

正好出现n次a

^

一行开头

D

任意非数字

a{n,}

至少出现n次a

$

一行末尾

w

任意字母数字或下划线

a{n,m}

出现n-m次a

(…)

括号用于分组

W

任意非字母数字或下划线

a*?

零个或多个a(非贪婪)

(a|b)

a或b

(a)…1

引用分组

(?=a)

前面有a

(?!a)

前面没有a

对于上面的代码我要做到三点:

  1. 图片 src 是真实地址的不能改,比如: src="http://url/to/real-image.jpg"
  2. 图片 src 是相对地址的,需要添加绝对地址: src="real-image.jpg" 改成 src="http://url/to/real-image.jpg"
  3. 图片 src 是懒加载图片的,修改为 data-echo 表示的绝对地址: src="http://url/to/imgloader.gif" data-echo="real-image.jpg" 改成 src="http://url/to/real-image.jpg"

第三种情况很好处理,正则表达式: /(http://url/to/imgloader.gif" data-echo=")/g 来进行替换即可 ,这里很多符号需要使用 反斜杠来转义,另外 g 表示全局搜索替换。

第二种情况和第一种情况很相似,但是第一种情况是不需要做任何修改的,刚开始我简单的替换 src=" 为绝对路径 src=http://url/to/ 是行不通的,这样会把第一种情况的图片地址也替换掉: src="http://url/to/http://url/to/real-image.jpg" 这是我不想要的结果!

所以,这里需要用到正则表达式中的不匹配原则了,如果路径中不包含 http:// 那么就是相对地址,需要修改!正则表达式是: /<img src="(?!http://). (.jpg|.png|.gif)"/gi ,显然, (?!http://) 是表示匹配字符串不包含 http:// 的意思,这里注意 i 表示不区分大小写进行搜索, . 表示匹配任何换行符之外的单个字符,然后 代表不止一个, (.jpg|.png|.gif) 表示这三种图片格式中的任何一种即可。这样正则表达式就达到匹配搜素的目的了。

另外,正则表达中括号 () 非常有用( (x)(?:x) 含义相反,可以参考相关资料 ),初学者很容易忽略这一点!它的含义和用途是:

(x) 匹配 x 并且记住匹配项,就像下面的例子展示的那样。括号被称为捕获括号。 模式 /(foo) (bar) 1 2/ 中的 (foo)(bar) 匹配并记住字符串 foo bar foo bar 中前两个单词。模式中的 12 匹配字符串的后两个单词。注意 12n 是用在正则表达式的匹配环节。在正则表达式的替换环节,则要使用像 $1$2$n 这样的语法,例如,'bar foo'.replace(/(...) (...)/, '$2 $1')

所以最终我的代码如下,我加了两个括号用于记住匹配项并用 $1$2 来使用,代码一目了然:

代码语言:javascript复制
if(feedConfig.replaceURL) {
    var regLazy = /(http://liuqingwen.me/blog/images/imgloader.gif" data-echo=")/g;
    var regSrc = /(<img src=")((?!http://). (.jpg|.png|.gif)")/gi;
    posts.forEach(function(post) {
        var coverdiv = post.permalink   post.cover_index;
        var contenthead = '<span class="image main"><img src="'   coverdiv   '" alt="'   post.title   '"></span>';
        var content = post.content.replace(regSrc, "$1"   post.permalink   "$2");
        content = content.replace(regLazy, post.permalink);
        //element.content = contenthead   content;
        post.newContent = contenthead   content;
    });
}

注意上面代码中我所注释的那段代码,我发现我并不能直接修改 element.content 那样会导致我所有博客文章和 RSS 文件一同被莫名其妙地改掉,这是我没有预料到的,所以,鉴于 JavaScript 的动态语言特性,我给每篇文章 post 动态地添加了一个属性: post.newContent 用于 RSS 的生成。

最后还需要在模板代码中进行应用:

代码语言:javascript复制
{% if config.feed.content and post.content and post.newContent %}
    <content type="html"><![CDATA[{{ post.newContent | safe }}]]></content>
{% elif config.feed.content and post.content %}
    <content type="html"><![CDATA[{{ post.content | safe }}]]></content>
{% endif %}

三、写在最后

其实我们在进行字符串匹配、替换、修改的时候,我们不一定完全需要使用正则表达式,特别是那些不复杂的情况,简单使用字符串的一些标准方法就可以进行查找替换修改了。但是,我觉得能用正则表达式就尽量使用正则表达式,有时候性能也不会差,我给出三点简单的原因:

1 正则表达式有时候并不慢

在对于长篇的文字匹配搜索的时候,正则表达式表达更加合理,速度也不慢,我觉得优先使用正则表达式。虽然我也没有理论支持,但是想想,正则表达式为啥存在于各种语言之中?是吧。

2 我所熟悉的 Java 中 replaceAll 函数

这个函数表面上和 replace 一样,实际上它的第一个参数是一个正则表达式而非字符,所以 "1.2.3".replaceAll(".", "-") 的结果不是 1-2-3 而是 ----- ,因为 "." 是正则表达式代表任何非空字符的匹配规则啊。

3 正则表达式在不同语言中基本通用

不一定是 JavaScript ,对于 Java 或者其他语言都能通用正则表达式,看来学习它是很有必要的,你说呢?

参考资料:

正则表达式(MDN - Mozilla Developer Network): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions

正则表达式中的不匹配: http://www.isnowfy.com/regular-expression-negative/

EJS (GitHub): https://github.com/tj/ejs

SWIG (GitHub): https://github.com/paularmstrong/swig

PUG (GitHub): https://github.com/pugjs/pug

0 人点赞