【问题标题】:Lua - How to find a substring with 1 or 2 characters discrepancyLua - 如何找到具有 1 或 2 个字符差异的子字符串
【发布时间】:2012-10-09 18:07:28
【问题描述】:

假设我有一个字符串

local a = "Hello universe"

我通过

找到子字符串“universe”
a:find("universe")

现在,假设字符串是

local a = "un#verse"

要搜索的字符串是universe;但子字符串相差一个字符。 所以显然 Lua 忽略了它。

即使单个字符存在差异,如何让函数找到字符串?

【问题讨论】:

标签: string lua string-matching


【解决方案1】:

如果您知道字符的位置,请使用 . 代替该字符:a:find("un.verse")

但是,您似乎正在寻找模糊字符串搜索。它超出了 Lua string 库的范围。您可能想从这篇文章开始:http://ntz-develop.blogspot.com/2011/03/fuzzy-string-search.html

至于 Lua 模糊搜索实现——我没有使用过任何实现,但是搜索“lua 模糊搜索”会给出一些结果。有些是基于这篇论文的:http://web.archive.org/web/20070518080535/http://www.heise.de/ct/english/97/04/386/

试试https://github.com/ajsher/luafuzzy

【讨论】:

  • 哎呀!我没有意识到这是一个复杂的问题......对于我目前非常微不足道的需求来说,当然不值得实现这个..虽然它看起来是一个非常有趣的话题..有一天可能会有用:)谢谢你的回复!
【解决方案2】:

听起来你想要类似TRE 的东西:

TRE 是一个轻量级、强大且高效的 POSIX 兼容正则表达式匹配库,具有一些令人兴奋的功能,例如近似(模糊)匹配。

近似模式匹配允许匹配是近似的,也就是说,允许匹配在某种接近度度量下接近搜索到的模式。 TRE 使用编辑距离度量(也称为 Levenshtein 距离),可以在搜索文本中插入、删除或替换字符以获得精确匹配。每次插入、删除或替换都会增加匹配的距离或成本。 TRE 可以报告成本低于某个给定阈值的匹配。 TRE 也可用于搜索成本最低的匹配项。

它的 Lua 绑定作为 lrexlib 的一部分提供。

【讨论】:

  • 整洁的小库.. 不幸的是,我无法将 C 库集成到我的程序中。所以这是窗外:(
【解决方案3】:

如果您真的在寻找单个字符差异并且不关心性能,那么这里有一个简单的方法应该可行:

local a = "Hello un#verse"

local myfind = function(s,p)  
  local withdot = function(n)
    return p:sub(1,n-1) .. '.' .. p:sub(n+1)
  end
  local a,b
  for i=1,#s do
    a,b = s:find(withdot(i))
    if a then return a,b end
  end
end

print(myfind(a,"universe"))

【讨论】:

    【解决方案4】:

    一个简单的滚动你自己的方法(基于模式保持相同长度的假设):

    function hammingdistance(a,b)
        local ta={a:byte(1,-1)}
        local tb={b:byte(1,-1)}
        local res = 0
        for k=1,#a do
            if ta[k]~=tb[k] then
                res=res+1
            end
        end
        print(a,b,res) -- debugging/demonstration print
        return res
    end
    
    function fuz(s,pat)
        local best_match=10000
        local best_location
        for k=1,#s-#pat+1 do
            local cur_diff=hammingdistance(s:sub(k,k+#pat-1),pat)
            if  cur_diff < best_match then
                best_location = k
                best_match = cur_diff
            end
        end
        local start,ending = math.max(1,best_location),math.min(best_location+#pat-1,#s)
        return start,ending,s:sub(start,ending)
    end
    
    s=[[Hello, Universe! UnIvErSe]]
    print(fuz(s,'universe'))
    

    免责声明:不推荐,仅供娱乐:

    如果你想要更好的语法(而且你不介意弄乱标准类型的元表),你可以使用这个:

    getmetatable('').__sub=hammingdistance
    a='Hello'
    b='hello'
    print(a-b)
    

    但请注意 a-b 这样不等于 b-a

    【讨论】:

    • 请注意,混淆标准类型通常被认为是一种不好的风格。
    • 但这很有趣!唯一遗憾的是,您无法覆盖标准运算符以使 1+1 == 3 ;)。但确实是坏作风。已添加免责声明。
    • @jpjacobs 感谢您的代码。虽然表演会大受欢迎(二次时间?),不是吗?而且我会比较很多词,所以...
    • 这一切都取决于。如果是解析用户输入,没问题,用户会比较慢。否则,只需尝试一下,然后衡量性能影响。
    猜你喜欢
    • 1970-01-01
    • 2020-05-16
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2020-04-01
    • 2015-11-11
    • 1970-01-01
    相关资源
    最近更新 更多