我编写的模式仅适用于单字符子字符串,例如作为测试用例的提问者。跳到下一个粗体标题以查看该答案,或继续阅读以了解他们在尝试中做错的一些事情的解释。跳到最后的粗体标题,了解多字符子字符串的通用、低效解决方案
我尝试使用 lua mystring:find 重新创建 python mystring.rfind 的输出,它仅适用于单字符子字符串。稍后我将向您展示一个适用于所有情况的函数,但它是一个非常糟糕的循环。
作为回顾(以解决您做错的事情),让我们谈谈mystringvar:find("pattern", index),string.find(mystringvar, "pattern", index) 的糖。这将返回 start, stop 索引。
可选的索引设置开始,而不是结束,但负索引将从“右减索引”倒数到字符串结尾(-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 无论如何只返回起始索引,所以这应该是一个合适的替换。
让我们重新阅读代码,看看它是如何工作的:
子我已经解释过了
string.find 中不再需要索引
好的,这是什么模式"\n[^\n]-$"?
$ - 锚定到句尾
[^x] - 匹配“非 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
如果您想查看我为this 提供的整个“测试套件”...