使用LPeg将文本转换为维基格式

长的故事即将展开,但我会尽量简短。我从一个系统中提取出许多纯文本段落,然后以维基格式重新输出,以便复制所述数据不是一项繁琐的任务。这一切进展顺利,除了没有自动生成用于我们页面的“主题”的参考,“主题”需要通过阅读所有文本并手动更改"Topic"为"[[Topic]]"来添加。

第一要求:每个主题只有第一次出现才可单击链接,否则会变成一个真正的 spammy 链接,并且会影响可读性。为了避免与以同样的单词开头的主题出现问题。

第二要求:重叠的主题名称应当以这样的方式处理,即最“精确”的主题获取链接,而在后续出现中,不太精确的主题不会链接,因为它们可能不正确。

示例:

` topics = {"Project","Mary","Mr. Moore","Project Omega"} input = "Mary and Mr. Moore work together on Project Omega. Mr. Moore hates both Mary and Project Omega, but Mary simply loves the Project." output = function_to_be_written(input) --“[[Mary]]和[[Mr. Moore]]共同在[[Project Omega]]上工作。 Mr. Moore 讨厌玛丽和 Project Omega,但 Mary 简单地喜欢[[Project]]。” `

现在,我迅速发现简单或复杂的 string.gsub() 不能为我提供满足第二要求的内容,因为它没有提供一种说“将此匹配视为不存在-我想要你进一步回溯”的方法。我需要引擎执行类似于以下操作:

` input = "abc def ghi" --循环输入时,按以下顺序匹配以下字符串: --1)abc def ghi --2)abc def --3)abc --4)def ghi --5)def --6)ghi `

一旦字符串与实际主题匹配并且尚未由其wikified版本替换,就会替换。如果该主题以前已被替换为已造成过的版本,则不进行替换,而是继续在该主题的末尾匹配(因此对于主题“abc def”,在两种情况下都会测试“ ghi”下一个)。

因此,我到达了 LPeg。我已经研究了它,玩了它,但它非常复杂,虽然我认为我需要以某种方式使用 lpeg.Cmtlpeg.Cs,但我无法正确地混合两者以使我想要的工作有效。我正在避免发布我练习的尝试,因为它们的质量很低,可能会让任何人更困惑,而不是帮助澄清我的问题。

(为什么我想使用 PEG 而不是自己编写三重的嵌套循环呢?因为我不想,而这是学习 PEG 的好借口..只是我有些超过自己的能力。除非无法使用 LPeg,否则第一个选项不可取。)

原文链接 https://stackoverflow.com/questions/2706429

点赞
stackoverflow用户202914
stackoverflow用户202914

所以为什么不使用 string.find 呢?它只搜索第一个主题出现的位置,并给出其起始索引和长度。你所要做的就是在结果中添加 [[ 。 对于每个块,复制主题表并在找到第一个出现后将其删除。 按长度对主题进行排序,最长的排在最前面,以便首先找到最相关的主题。

LPeg 是一个很好的工具,但在这里使用它并不必要。

2010-04-29 08:39:04
stackoverflow用户282536
stackoverflow用户282536

我感到无聊,需要做点什么:

topics = { "Project", "Mary", "Mr. Moore", "Project Omega"}

pcall ( require , 'luarocks.require' )
require 'lpeg'
local locale = lpeg.locale ( )
local endofstring = -lpeg.P(1)
local endoftoken = (locale.space+locale.punct)^1

table.sort ( topics , function ( a , b ) return #a > #b end ) -- Sort by word length (longest first)
local topicpattern = lpeg.P ( false )
for i = 1, #topics do
    topicpattern = topicpattern + topics [ i ]
end

function wikify ( input )
    local topicsleft = { }
    for i = 1 , #topics do
        topicsleft [ topics [ i ] ] = true
    end

    local makelink = function ( topic )
        if topicsleft [ topic ] then
            topicsleft [ topic ] = nil
            return "[[" .. topic .. "]]"
        else
            return topic
        end
    end

    local patt = lpeg.Ct (
        (
            lpeg.Cs ( ( topicpattern / makelink ) )* #(-locale.alnum+endofstring) -- Match topics followed by something thats not alphanumeric
            + lpeg.C ( ( lpeg.P ( 1 ) - endoftoken )^0 * endoftoken ) -- Skip tokens that aren't topics
        )^0 * endofstring -- Match adfinum until end of string
    )
    return table.concat ( patt:match ( input ) )
end

print(wikify("Mary and Mr. Moore work together on Project Omega. Mr. Moore hates both Mary and Project Omega, but Mary simply loves the Project.")..'"')
print(wikify("Mary and Mr. Moore work on Project Omegality. Mr. Moore hates Mary and Project Omega, but Mary loves the Projectaaa.")..'"')

我首先创建了一个模式,匹配所有不同的主题;我们希望首先匹配最长的主题,因此按字长从长到短对表进行排序。 现在我们需要制作一个列表,其中包含当前输入中未看到的主题。 如果我们没有看到它,makelink将引用/链接该主题,否则将保持其原样。

现在是真正的lpeg内容:

  • lpeg.Ct将所有捕获打包到表中(以用于输出连接)
  • topicpattern / makelink捕获主题,并将其通过我们的makelink函数传递。
  • lpeg.Cs替换了makelink的结果,其中匹配了主题。
  • + lpeg.C ( ( lpeg.P ( 1 ) - locale.space )^0 * locale.space^1 )如果我们没有匹配到主题,请跳过一个单词(即不是由空格后跟空格的空间)
  • ^0重复。

希望这就是你想要的 :)

Daurn

注:编辑了代码,描述不再正确

2010-05-02 12:31:25