使用vscode全局正则搜索并替换解决hexo语法报错

前言

之前用python从网络爬了一些引流文, 在使用hexo渲染时出现大批量的报错, 如下:

1
2
3
4
5
6
7
8
{% raw %}
Nunjucks Error: [Line 103, Column 93] expected variable end
===== Context Dump =====
=== (line number probably different from source) ===

103 | <p>在Go的模板语法中,使用<code>range</code>关键字进行遍历,其中pipline的值必须是数组、切片、map或者channel。其语法以<code>{{range pipline}}</code>开头,以<code>{{end}}</code>结尾,形式如下:</p>
{% endraw %}
===== Context Dump Ends =====

该错误是由于Nunjucks模板引擎将文档中的双花括号{{}}误解析为模板语法导致的冲突

解决方案也很简单, 那就是在双花括号前后添加raw标签包裹, 如下:

1
{% raw %}{{xxx}}{% endraw %}  <!-- raw标签包裹 -->

其目的是告诉Nunjucks将花括号当做普通文本来显示

大批量替换

如果只是一两处修改还好, 问题是大量的文章存在这样的问题, 手动一一修改肯定不现实

要不写一个python脚本自动替换一下?

可是可以, 没有办法的情况下只能这么干, 不过目前来说大可不必, 我们其实可以借助IDE的全局正则搜索替换功能, 比如vscode

具体操作

  1. 打开替换面板 快捷键Ctrl+H (Windows/Linux)Cmd+Option+F (macOS)

  2. 启用正则表达式模式 (点击.* 按钮或按 Alt+R

  3. 搜索框输入:

    1
    2
    3
    4
    5
    {% raw %}
    `(\{\{[^{}]*?\}\})`
    或者
    `(\{\{+.*?\}\}+)`
    {% endraw %}
    • [^{}] 确保只匹配非花括号字符
    • *? 非贪婪匹配任意数量字符
  4. 替换框输入:

    1
    `{% raw %}$1{% endraw %}`
  5. 执行全部替换

image-20250906152802218

优化点说明:

  1. 排除嵌套情况:[^{}]确保不会错误匹配{{a{b}c}}这类嵌套结构
  2. 精确匹配:*?.更安全,避免过度匹配
  3. 保留原格式:$1会保持原变量的大小写和特殊字符

特殊场景处理:

  • 若需包含换行符:改为[\s\S]*?
  • 若需排除特定前缀:使用(?<!prefix)\{\{

常见语法冲突字符

除了双花括号之外, 还有类似的字符也需要进行替换, 不然hexo渲染也会报错, 下面列举一些常见的需要去除或者替换的字符

hexo标题不允许出现以下字符:

1
2
3
4
:
|
"
`

hexo内容需要进行替换的字符:

1
2
3
4
5
6
7
8
9
10
11
12
{% raw %} 这个忽略
{{}}
{{ 未闭合标签也不行
{{{}}}
{{xxx}} xxx表示任意内容
{% if ... %}
{% endif %}
{% else %}
{% elseif %}
{% xxx %}
{#xxx} 正确写法应该是{#xxx#} 不然报错expected end of comment
{% endraw %}这个忽略

对于{% xxx %}的替换, 可以使用以下搜索正则表达式:

1
\{%(?!(?:\s*raw\s|\s*endraw\s))([^%]+)%\}

替换内容:

1
{% raw %}{%$1%}{% endraw %}

说明:

  • 使用(?:)非捕获组同时排除rawendraw标签
  • \s*允许标签内可能存在的空格
  • 完整保留原始URL内容(通过$1引用)

image-20250906164948702

其他报错问题

  1. 提示标签未闭合

    1
    2
    Template render error: (unknown path)
    Error: expected end of comment, got end of file

    往往是因为出现了类似于{#xxx}的语法, 正确写法应该是{#xxx#}

    如果数量比较多 可以使用正则搜索替换:

    • 在搜索框中输入:\]+)\}
    • 在替换框中输入:``

如果碰上更复杂情况, 比如{#user,#user}, 也是会报错的, 这时我们可以使用增强表达式:

1
(?:^|(?<!\{% raw %\}))\{#([^#]*(?:#(?!\})[^#]*)*)\}(?!\s*\{% endraw %\})

替换成:

1
{% raw %}{#$1}{% endraw %}
  1. 提示unexpected token

    1
    2
    3
    4
    {% raw %}
    Nunjucks Error: [Line 94, Column 162] unexpected token:
    94 | <p>要想保证双花括号初始化不会出现内存泄漏的办法也很简单,只需要被 <code>static</code> 修饰即可,但这样做还是存在潜在的风险,可能会被某人不小心删除掉,于是我们另寻它道,发现了可以使用 Java8 中的 Stream 或 Java9 中的集合工厂 <code>of</code> 方法替代"{{"。</p>
    {% endraw %}

    问题处在未闭合的{{

    解决方案就是使用raw标签对花括号进行包裹

    如果数量比较多, 则依然使用正则全局替换, 在搜索框中输入以下正则表达式:

    1
    \{\{(?!(?:[^{}]*}}))

    然后在替换框中输入:

    1
    {% raw %}{{{% endraw %}

    表达式解释:

    • \{\{- 匹配 {{字面量(转义特殊字符)
    • (?!(?:[^{}]*}}))- 负向先行断言,确保后面没有 }}闭合标签
    • (?:[^{}]*}})- 匹配任意非 {}字符后跟 }}
    • ?!- 表示后面不能跟着这个模式

    这个正则表达式只会匹配未闭合的 {{ 标签,而不会匹配已闭合的 {{...}} 标签。

总结

根据上面的探讨, 我们来做一个整合

按照以下步骤依次替换 能解决90%以上的问题, 剩下的手动改一下即可:

  1. 第一步 替换带引号的{% xxx %}

    1
    `\{%(?!(?:\s*raw\s|\s*endraw\s))([^%]+)%\}`

    替换:

    1
    `{% raw %}{#$1}{% endraw %}`
  2. 第二步 替换带引号{{}}

    搜索:

    1
    2
    3
    `\{\{`

    `\}\}`

    替换:

    1
    2
    3
    `{% raw %}{{{% endraw %}`

    `{% raw %}}}{% endraw %}`
  3. 第三步 替换带引号{{xxx}}

    搜索:

    1
    `(\{\{+.*?\}\}+)`

    替换:

    1
    `{% raw %}$1{% endraw %}`
  4. 第四步 替换{#xxx}

    搜索:

    1
    (?:^|(?<!\{% raw %\}))\{#([^#]*(?:#(?!\})[^#]*)*)\}(?!\s*\{% endraw %\})

    替换:

    1
    {% raw %}{#$1}{% endraw %}
  5. 第五步 替换不带引号的{{xxx}}

    由于没有引号限制, 覆盖的范围会更广, 包括代码和注释

    搜索:

    1
    (\{\{+.*?\}\}+)

    替换:

    1
    {% raw %}$1{% endraw %}
  6. 第六步 替换不带引号{% xxx %}

    搜索:

    1
    \{%(?!(?:\s*raw\s|\s*endraw\s))([^%]+)%\}

    替换:

    1
    {% raw %}{#$1}{% endraw %}

前三步可以放心大胆替换, 后面几步按需替换, 因为有些代码里面的花括号可以保留

补充

如果你想省事, 以牺牲文章部分内容和格式的前提下, 还有一种简单粗暴且有效的方法

那就是把整篇文章进行raw标签包裹, 也就是文章开头加一个raw标签, 文章结尾加一个endraw标签

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

0%