+ 网站

jekyll Liquid 数组增删改的实现
2022-05-24

目录:

jekyll 是一个简单的静态博客生成器,通过 Liquid 处理模版文件,将 Markdown 文件转换成网页。通过 Liquid 提供的语法,可以实现相对简单的功能实现。

Liquid

首先介绍一下 Liquid ,Liquid 是一门开源的模板语言,由 Shopify 创造并用 Ruby 实现。
虽然 Liquid 提供了许多内置语法,但还是无法满足实际的使用需求,在近半个月的使用中,Liquid 对常见的数组存储修改操作的缺失几乎让我抓狂。不过好在对于字符串和列表的简单操作是可行的,只需要把它们组合使用同样能达到想要的效果,这里记录下我仅使用字符串对数组存储操作的完整实现。

聊胜于无,先来看看 Liquid 提供的最基础的数组迭代操作。

Liquid 语法下的数组存储

Liquid 语法中通过 for 语句迭代出来的 Markdown 文本基本会存储在两三层的数组中,要取出所有数据必须逐层迭代取出数据。

{% for posts in site.posts %}
    {% for post in posts %}
        {{ post.title }}
    {% endfor %}
{% endfor %}

如果单独取出多纬数组中的数组变量,可以使用 map 过滤语句。

{% assign categories = site.pages | map: "category" %}

有一点需要知道的是,Liquid 提供了使用|过滤器的方式对变量进行操作类似 firstlast, uniq等方式对字符串过滤,且筛选的语句可以多次使用。 只要对迭代中的处理的数据进行修改,数组的其他操作是完全可能的。

数组元素增加

Liquid 无法直接操作数组,但是对字符串提供了很多可选的过滤操作,将数组直接转换为字符串操作,最后再转换回数组既可。

将数组转换字符串使用 array_to_sentence_string 语句过滤,同时使用 prepend 过滤语法的拼接为新的字符串

{{ assign str =  page.categories | reverse | array_to_sentence_string }}
=> python,jekyl,liquid,...

{% assign new_str = str | prepend: "," | prepend: str %}
{% assign list_new_str = new_str | split: "," | reverse %}

#{% assign list_new_str = str | prepend: "," | prepend: str | split: "," | reverse %}

数组的修改

对于数组的修改,将数组转换为字符串后使用 replace 过滤语句替换,再使用 split 过滤语句转换为数组既可。

{% assign str_list = "python, java, str" | split: ", " | array_to_sentence_string %}

{% assign list_new = str_list | replace:"java", "ruby" | split: "," %}

数组元素删除

数组的删除,同理转换为字符串操作 首尾的字符使用 slice 过滤语句进行反向切割,记得加上逗号计数 位于中间的字符,使用 replace 过滤语句进行替换

{% assign str_list = "python, java, str" | split: ", " | array_to_sentence_string %}

#字符在开头
{% assign list_new =  str_list | slice: 6, str_list.size %}

#字符在中间
{% assign list_new = str_list | replace:"java", str_list.first | split: "," | uniq %}

#字符在末尾
{% assign str_size = str_list.size | minus: 4 %}
{% assign list_new =  str_list | slice: 0, str_list.size %}

数组合并

合并两个原有的数组,使用 concat 过滤语句,如果针对字符串和数组的拼接,请先使用 split 过滤语句转为数组

{% assign old = "python, java" | split: ", " %}
{% assign new = "jekyll,liquid" | split: ", " %}

{% assign all = new | concat: old %}

concat 语句的对象必须是数组,如果是单个字符串,可以拼接自身作为假数组,再分割得到一个为数组,合并数组后使用 uniq 过滤语句去除假数据,例如

{% assign list = "jekyll" | split: ", " %}

{% assign str = "liquid" %}
{% assign list_fake_str = str | prepend: "," | prepend: str | split: ", " %} # => [liquid, liquid]

{% assign last_list = list | concat: list_fake_str | uniq %} # => [jekyll, liquid]

数组储存 for 循环中的值

在数组 for 循环迭代加入为字符串,同时加入特定符号,这里使用逗号间隔字符,split 进行分割,最后形成反序成新的数组。

下面以取出所有 Markdown 中去重后得到唯一年份为示例:

{% assign dateList = site.posts | group_by_exp:"post", "post.date" %}

{% for date in dateList %}
    {% assign year = date.name | date: "%Y" %}
    {% assign yearList = yearList | prepend:year | prepend:"," %}
{% endfor %}

{% assign years = yearList | remove_first: "," | split:"," | uniq | reverse %}

取出的数组是反序的,根据需求,使用reverse进行反序。
最后对取出的数组迭代,使用语法 {{ }} 取出既可。

探讨

习惯了语言原生 API 支持现在,已经很少有机会去思考实现的方法了。大多时候情况下,我们对这些方法只是拿来即用,探索底层功能的实现方式这对我们来说确实太过复杂了,但是需要去实现特定功能的时候应该学会发散思维,原有的方法不一定是最优解。

本文作者: Exisi 本文链接: 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。