【问题标题】:Regular expression matching liquid code正则表达式匹配液码
【发布时间】:2016-11-12 14:40:25
【问题描述】:

我正在使用 Jekyll 构建网站我想从给定的 HTML 文件中自动删除流动代码(和流动代码)。我在 Python 中使用正则表达式来做这件事,到目前为止我有这个:

\{.*?\}|\{\{.*?\}\}

由于我对液体(和 .html)不太熟悉,有人可以确认这足以满足我的目标吗?

这是我将使用的文件类型的示例:

<div class="post-preview">
    <div class="post-title">
        <div class="post-name">
            <a href="{{ post.url }}">{{ post.title }}</a>
        </div>
        <div class="post-date">
            {% include time.html %}
        </div>
    </div>

    <div class="post-snippet">
        {% if post.content contains '<!--break-->' %}
            {{ post.content | split:'<!--break-->' | first }}
            <div class="post-readmore">
                <a href="{{ post.url }}">read more-></a>
            </div>
        {% endif %}
    </div>
    {% include post-meta.html %}
</div>

在这种情况下,我的正则表达式有效,但我想确保我不会错过未来的任何东西。我可以采取一种骇人听闻的方式,并用 cmets 将所有流动代码包围起来

/* start_liquid */ {blalala} /* end_liquid */

但我正在寻找一种更优雅的方式来做到这一点。

【问题讨论】:

  • 投反对票的人能说出他们的理由吗?
  • 我实际上并没有投反对票,但我认为他们希望您提供一个流动代码示例以获得一个完整的工作示例。
  • 我检查了您提供的代码。它看起来不错,我在下面给你的正则表达式只匹配 {} 或 {{}} 所包含的代码。如下所述,我只会半自动替换。顺便用Kate验证一下……
  • 你能更详细地解释一下,你想用匹配的液体代码做什么?你想删除它还是用 cmets 包围它?为什么你的解决方案不优雅?我不明白缺少什么。
  • 所以,我有一堆像这样的 html 文件,我可能需要从流动代码中清除它们,然后注入具有类似功能的 javascript 代码。所以我不想手动四处插入 cmets,也不想在引入更多流动代码的任何时候再次放入 cmets。我也不想将 .html 文件与 Liquid 和 javascript 分开,因为我可能会决定在以后更改 HTML 本身。因此我的问题:)

标签: python html regex liquid


【解决方案1】:

Python-Liquid 中的 regular expressiontokenizer 对于您的用例来说可能有点过分,但可以处理 {% comment %}{% raw %} 块以及任何多行标签。仅靠简单的正则表达式无法处理的问题。

Python 的 re 文档中的 Writing a tokenizer 示例使用了相同的技术。

您可以使用python-liquid 过滤掉这样的 Liquid 令牌。

from liquid.lex import get_lexer
from liquid.token import TOKEN_LITERAL

s = """
<div class="post-preview">
    <div class="post-title">
        <div class="post-name">
            <a href="{{ post.url }}">{{ post.title }}</a>
        </div>
        <div class="post-date">
            {% include time.html %}
        </div>
    </div>

    <div class="post-snippet">
        {% if post.content contains '<!--break-->' %}
            {{ post.content | split:'<!--break-->' | first }}
            <div class="post-readmore">
                <a href="{{ post.url }}">read more-></a>
            </div>
        {% endif %}
    </div>
    {% include post-meta.html %}
</div>
"""

tokenize = get_lexer()
tokens = tokenize(s)
only_html = [token.value for token in tokens if token.type == TOKEN_LITERAL]
print("".join(only_html))

请注意,输出会在 Liquid 标记之外保留换行符。

<div class="post-preview">
    <div class="post-title">
        <div class="post-name">
            <a href=""></a>
        </div>
        <div class="post-date">
            
        </div>
    </div>

    <div class="post-snippet">
        
            
            <div class="post-readmore">
                <a href="">read more-></a>
            </div>
        
    </div>
    
</div>

【讨论】:

    【解决方案2】:

    不是说你应该,但你可以使用“肮脏”的解决方案,例如:

    {%\ (if)[\s\S]*?{%\ end\1\ %}|
    {%.+?%}|
    {{.+?}}
    

    这匹配所有提供的模板代码,请参阅a demo on regex101.com
    其他调整是扩展交替组 (if) 或完全使用解析器。

    【讨论】:

      【解决方案3】:

      我实际上并不了解液体,但我假设代码块总是包含在 {} 或 {{}} 中。我认为很难找到一个不匹配这样的正则表达式:

      print "This is my string with a number {}, cool!".format(42)
      

      我建议您使用编辑器打开您的 html 文件,该编辑器会突出显示您的正则表达式的所有匹配项。例如,Kate 或 Geany 可以做到这一点。比你可以半自动地用空字符串替换所有出现的地方。但是,我强烈建议不要在不检查之前替换代码中的所有出现。你很可能会替换一些重要的东西。

      我也会使用这个正则表达式:

      \{[^\}]*\}|\{\{[^\}]*\}\}
      

      编辑(参见上面的 cmets):

      据我了解,我认为您希望有可能使用 Liquid 或 javascript 拥有两个版本的代码。我想到的唯一优雅的解决方案是使用 git 来解决这个问题。您可以为项目创建两个独立的分支,一个用于 Liquid,一个用于 javascript。这使您可以分别处理两个版本,并让您能够在两个版本之间切换。

      编辑 2:

      我也不会放弃寻找更好的解决方案。您还可以重新发布您的问题,让其他用户更清楚您的问题。可能有更优雅的解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-03-30
        • 2011-05-01
        • 1970-01-01
        相关资源
        最近更新 更多