# 使用 DSL 管理你的正则表达式

- Link: https://www.ixiqin.com/2023/04/02/using-a-dsl-manage-your-regular-expressions/
- Published: 2023-04-02T16:21:46+08:00
- Author: 白宦成

最近在写 LCTT 译文的解析工具，写正则、调试正则的过程非常的痛苦。

比如，下面的这个正则表达式就是我用来提取文章的英文标题的正则。由于 LCTT 的文章元
信息存储历史上出现过多次，所以我不得不写一个比较复杂的正则来匹配出想要的结果。

比如，下面的这段代码是我用来从文件路径当中提取出不同内容的正则，看起来十分复杂，
对吧？

    ```shcb-line-numbers
    /(?<collectDate>(?<type>(?<path>\.\/)(?:published))\/(?<yearOrSeries>(?:.+)?)\/(?<month>(?<=\d+)\.(?=\d+))?)(?:⭐️|⭐️⭐️)?(?<title>.+)\.md/
    ```

相比于看起来复杂，更加麻烦的是可维护性。正则表达式的可维护性相比于正常我们熟悉的
编程语言来说，是差了一大截。基本上如果要对上述这段正则表达式进行修改或者二次开发，
难度极高。但借助一些工具，我们可以使用类似 DSL 的方式来管理正则表达式，则可以以一个
更友好的方式来维护你的正则表达式。

![](https://files.ixiqin.com/2023/04/23163407/d2b5ca33bd970f64a6301fa75ae2eb22-1024x437.
png)

比如，以我为例，上面这张图片中的定义，便是上方正则的等价替换。虽然写了更多的代码，
但确实可读性、易于理解性和易于维护性，有了显著的提升。

想要使用，也不复杂，只需要使用对应的 DSL 语法来完成定义，即可完成正则表达式的构建。
以我上面的这段正则为例，我使用的是 javascript 的 [`magic-regexp` ](https://regexp.dev/)
包，实际使用时，大概是这样的，定义出对应的正则，直接基于其进行匹配即可。

    ```javascript
    const magicRegxp = require('magic-regexp');
    const { createRegExp, exactly, oneOrMore, char, anyOf, carriageReturn, global, multiline, linefeed, maybe, digit } = magicRegxp;

    const regExp = createRegExp(
                exactly("./").groupedAs("path")
                .and(anyOf("published")).groupedAs("type")
                .and(exactly("/"))
                .and(maybe(oneOrMore(char)).groupedAs("yearOrSeries"))
                .and(exactly("/"))
                .and(maybe(
               exactly(".").after(oneOrMore(digit)).before(oneOrMore(digit)).groupedAs("month")
                )).as("collectDate")
                .and(maybe(
                    exactly("⭐️").or(exactly("⭐️⭐️"))
                ))
                .and(exactly(oneOrMore(char)).groupedAs("title"))
                .and(exactly(".md")
            ));
    let result = regExp.exec(file_content);
    console.log(result.groups.title);
    Code language: JavaScript (javascript)
    ```

当然，这样的维护方式，在不同的语言下有着类似的实现，如果你使用 Golang ，那么 [Rex](https://github.com/hedhyw/rex)，
也是一个不错的选择。
