为了账号安全,请及时绑定邮箱和手机立即绑定

我如何在 Lua 中使用参数实现 rfind ?

我如何在 Lua 中使用参数实现 rfind ?

莫回无 2023-09-05 21:07:15
例如,我想在lua中做这样的事情:s = "Hey\n There And Yea\n"print(s.rfind("\n", 0, 5))我尝试在 lua 中使用 string.find 函数进行此操作:local s = "Hey\n There And Yea\n"local _, p = s:find(".*\n", -5)print(p)但这些并没有产生相同的结果。我做错了什么,如何解决这个问题,使其与 rfind 相同?
查看完整描述

2 回答

?
智慧大石

TA贡献1946条经验 获得超3个赞

Lua 有一个鲜为人知的函数string.reverse,可以反转字符串中的所有字符。虽然很少需要这样做,但该函数通常可用于在字符串内进行反向搜索。因此,要实现rfind,您需要在反向原始字符串中搜索反向模式,最后进行一些算术以获得与原始字符串的偏移量。这是模仿 Python 的代码:rfind


function rfind(subject, tofind, startIdx, endIdx)

    startIdx = startIdx or 0

    endIdx = endIdx or #subject

    subject = subject:sub(startIdx+1, endIdx):reverse()

    tofind = tofind:reverse()

    local idx = subject:find(tofind)

    return idx and #subject - #tofind - idx + startIdx + 1 or -1

end


print(rfind("Hello World", "H")) --> 0

print(rfind("Hello World", "l")) --> 9

print(rfind("foo foo foo", "foo")) --> 8

print(rfind("Hello World", "Toto")) --> -1

print(rfind("Hello World", "l", 1, 4)) --> 3

请注意,此版本rfind使用 Python 索引约定,从 开始,如果未找到字符串则0返回。在 Lua 中使用基于 1 的索引并在没有匹配时-1返回会更加连贯。nil修改将是微不足道的。


查看完整回答
反对 回复 2023-09-05
?
繁华开满天机

TA贡献1816条经验 获得超4个赞

我编写的模式仅适用于单字符子字符串,例如提问者用作测试用例的子字符串。跳到下一个粗体标题以查看答案,或者继续阅读以了解他们在尝试中做错的一些事情的解释。跳到最后的粗体标题,以获得多字符子字符串的通用、低效解决方案


我尝试mystring.rfind使用 lua重新创建 python 的输出mystring:find,它仅适用于单字符子字符串。稍后我将向您展示一个适用于所有情况的函数,但这是一个非常糟糕的循环。


作为回顾(为了解决你做错的事情),让我们来谈谈mystringvar:find("pattern", index), 的糖string.find(mystringvar, "pattern", index)。这将返回start, stop索引。


可选的 Index 设置开始,而不是结束,但负索引将从“右减索引”向后计数到字符串末尾(索引 -1 将仅计算最后一个字符,-2 将计算最后 2 个字符)。这不是期望的行为。


您不应尝试使用索引来创建子字符串,而应该创建如下所示的子字符串:

mystringvar:sub(start, end)将从头到尾提取并返回子字符串(1 个索引,包括结尾)。因此,要重新创建 Python 的 0-5(0 索引,独占结尾),请使用 1-5。


现在请注意,这些方法可以链接在一起string:sub(x, y):find(""),但为了便于阅读,我将其分解。话不多说,我向您介绍:

答案


local s = "Hey\n There And Yea\n"

local substr = s:sub(1,5)

local start, fin = substr:find("\n[^\n]-$")

print(start, ",", fin)

我有一些半措施解决方案,但为了确保我所编写的内容适用于多个子字符串实例(1-5 子字符串仅包含 1),我使用子字符串和整个字符串进行了测试。观察:

用 sub(1, 5) 输出: 4   ,  5

用 sub(1, 19) 输出(整个长度):19   ,  19


它们都正确地报告了最右边子字符串的开头,但请注意,“fin”索引位于句子的末尾,我将在稍后解释。我希望这没问题,因为 rfind 无论如何都只返回起始索引,所以这应该是一个合适的替代品。


让我们重读一下代码,看看它是如何工作的:

sub 我已经解释过了

string.find 中不再需要索引 好吧

,这个模式是什么"\n[^\n]-$"?

$- 锚定到句子末尾

[^x]- 匹配“not x”

-- 前一个字符或集合(在本例中为 )的匹配尽可能少(甚至 0)[^\n]。这意味着如果一个字符串以您的子字符串结尾,它仍然可以工作)

它以 \n 开头,所以总的来说它的意思是:“给我一个换行符,但后面没有其他换行符,直到句子结尾”。这意味着即使您的子字符串仅包含 1 个 \n 实例,如果您要在具有多个子字符串的字符串上使用此函数,您仍然会获得最高索引,就像 rfind 一样。


请注意, string.find 不符合模式组 ( ()),因此将其包装\n在组中是徒劳的。因此,我无法阻止末端锚定$将变量扩展fin到句子的末尾。


我希望这对你有用。


对任意长度的子字符串执行此操作的函数

我不会解释这一点。


function string.rfind(str, substr, plain) --plain is included for you to pass to find if you wish to ignore patterns

  assert(substr ~= "") --An empty substring would cause an endless loop. Bad!

  local plain = plain or false --default plain to false if not included

  local index = 0

  --[[

    Watch closely... we continually shift the starting point after each found index until nothing is left. 

        At that point, we find the difference between the original string's length and the new string's length, to see how many characters we cut out. 

  ]]--

  while true do

    local new_start, _ = string.find(str, substr, index, plain) --index will continually push up the string to after whenever the last index was.

    if new_start == nil then --no match is found

            if index == 0 then return nil end   --if no match is found and the index was never changed, return nil (there was no match)

      return #str - #str:sub(index)  --if no match is found and we have some index, do math.

    end

    --print("new start", new_start)

    index = new_start + 1 --ok, there was some kind of match. set our index to whatever that was, and add 1 so that we don't get stuck in a loop of rematching the start of our substring.

  end

end

如果您想查看我的整个“测试套件” ......


查看完整回答
反对 回复 2023-09-05
  • 2 回答
  • 0 关注
  • 185 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信