• Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:FormatString

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

这是一个进行字符串格式化的模块,采用AC自动机作为字符串匹配算法。

与string.format相比,支持自定义占位符。与使用string.gsub进行匹配与替换相比,在模式串较多时有速度优势。

方法

buildTrie(format)

功能

将格式化参数列表转化为一个字典树。这个字典树可以反复使用。

参数

  1. format:格式化参数列表,是一个Lua的table,并具有如下形式:
{
    {
        format = "%d",
        callback = function(matched_times, extras) 
            mw.log('%d matched')
            return tostring(extras[matched_times]) 
        end
    },
    {
        format = "%f",
        callback = function(matched_times, extras) 
            mw.log('%f matched')
            return tostring(extras[matched_times]) 
        end
    },
    ...,
    {
        format = "%s",
        callback = function(matched_times, extras) 
            mw.log('%s matched')
            return tostring(extras[matched_times]) 
        end
    }
}

其中,format代表待匹配的占位符。

当匹配到某一个占位符时,对应的callback函数将会被调用。此函数应该返回一个字符串,原先的占位符将被这个字符串替换。

callback函数的第一个参数matched_times表示这是第几次匹配到占位符;第二个参数extras为附加数据,通常是待填充的真实值。

需要注意的是,某一个占位符不应该是另一个占位符的前缀,如以下写法是不合法的:

{
    {
        format = "her",
        callback = ...
    },
    {
        format = "he",      -- he是her的一个前缀
        callback = ...
    }
}

返回值

建立的字典树。

replaceStr(str, trie, extras)

功能

对字符串str进行格式化。

参数

  1. str:待格式化的字符串。
  2. trie:建立的字典树。
  3. extras:附加数据,通常是待填充的真实值。你非要用全局变量我也没办法。

返回值

格式化完成后的字符串。

例子

local FormatString = require("Module:FormatString")
local formatList = {
    {
        format = "%d",
        callback = function(matched_times, extras) 
            return tostring(extras[matched_times]) 
        end
    },
    {
        format = "%f",
        callback = function(matched_times, extras) 
            return tostring(extras[matched_times]) 
        end
    },
    {
        format = "%X",
        callback = function(matched_times, extras) 
            return string.format('%X', extras[matched_times])
        end
    }
}
local trie = FormatString.buildTrie(formatList)
mw.log(FormatString.replaceStr('%d %f', trie, { 1, 0.25 }))
mw.log(FormatString.replaceStr('%d,%X,%f', trie, { 5, 10, 2.33 }))

预期输出:

1 0.25
5,A,2.33

未实现的功能

  1. 占位符中包含统配符或正则表达式以匹配参数。
local queue = require("Module:queue")

local FormatString = {}

function FormatString.buildTrie(format)
    root = {}
    root.next = {}
    for i, item in ipairs(format) do
        local cur = root
        for i = 1, mw.ustring.len(item.format), 1 do 
            local c = mw.ustring.sub(item.format, i, i)
            if cur.next[c] == nil then
                cur.next[c] = {} -- new node
                cur.next[c].next = {} 
                cur.next[c].father = cur
                cur.next[c].char = c
            end
            cur = cur.next[c]
        end
        cur.callback = item.callback
        cur.len = mw.ustring.len(item.format)
    end
    root.fail = {}
    local q = queue
    q:push(root)
    while not(q:empty()) do
        local cur = q:front()
        q:pop()
        for i, t in pairs(cur.next or {}) do
            q:push(t)
        end
        if (cur ~= root) and (cur.father ~= root) then
            cur2 = cur.father
            while cur2.fail.next[cur.char] ~= nil and cur2 ~= root do
                cur2 = cur2.fail
            end
            cur.fail = cur2.fail.next[cur.char] or root
        else
            cur.fail = root
        end

    end
    return root
end

function FormatString.replaceStr(str, trie, extras)
    local cur_state = trie
    local i = 1
    local matched_times = 0
    while i <= mw.ustring.len(str) do
        local c = mw.ustring.sub(str, i, i)
        while cur_state.next[c] == nil and cur_state ~= trie do
            cur_state = cur_state.fail or trie
        end
        cur_state = cur_state.next[c] or trie
        if cur_state.callback ~= nil then
            matched_times = matched_times + 1
            local newStr = cur_state.callback(matched_times, extras)
            -- mw.log(mw.ustring.sub(str, i - cur_state.len + 1, i)..' -> '..newStr)
            str = mw.ustring.sub(str, 1, i - cur_state.len)..newStr..mw.ustring.sub(str, i + 1, mw.ustring.len(str))
            i = i + mw.ustring.len(newStr) - cur_state.len
            cur_state = trie
        end
        i = i + 1
    end
    return str
end

return FormatString