在字符串中查找字符的最后一个索引

10

我希望能够在我的Lua(Luvit)项目中使用字符串的lastIndexOf方法。不幸的是,这种方法没有内置在Lua中,我现在有点困难。

在Javascript中它看起来像:

'my.string.here.'.lastIndexOf('.')     // returns 14

3
你究竟想要解决什么问题? - lhf
2
我认为最简单的方法就是使用 string.find ('my.string.here.'):find("%.[^.]-$")。但你需要转义特殊字符(例如 ., *, + 等)。在 Lua 中,结果应该是 15。 - moteus
@moteus 提供的建议不错,但我想要一个通用的解决方案(例如查找数字的索引)。 - Kosmetika
@lhf 你为什么要问这个问题?在所有编程语言中,字符串在子字符串中的第一个和最后一个索引都是广泛使用的函数!他没有必要解释任何特定的问题... - Tomáš Zato
5个回答

10
function findLast(haystack, needle)
    local i=haystack:match(".*"..needle.."()")
    if i==nil then return nil else return i-1 end
end
s='my.string.here.'
print(findLast(s,"%."))
print(findLast(s,"e"))

请注意,要查找 . ,您需要对其进行转义。


4
如果你有性能方面的顾虑,那么如果你使用的是使用LuaJIT的Luvit,它可能会更快一些。
local find = string.find
local function lastIndexOf(haystack, needle)
    local i, j
    local k = 0
    repeat
        i = j
        j, k = find(haystack, needle, k + 1, true)
    until j == nil

    return i
end

local s = 'my.string.here.'
print(lastIndexOf(s, '.')) -- This will be 15.

请记住,Lua字符串从1开始,而不是像JavaScript一样从0开始。


发现了这篇有关性能的有趣帖子 - https://neil.fraser.name/news/2009/12/25/,只是好奇这个回答是否符合性能要求 - https://dev59.com/aWIj5IYBdhLWcg3wPzDH#20460403? - Kosmetika
1
@Kosmetika 确实很有趣。我之前没有看到过,但是我写的函数与 lastIndexOfFind 非常接近。唯一的区别是我的函数返回 nil 而不是 -1,这更符合 Lua 的风格。哦,我的函数从 string.find 的第二个返回值开始,这意味着它跳过了一些不必要 - Ryan Stein

3

要在haystack中查找字符串needle的最后一个实例:

function findLast(haystack, needle)
    --Set the third arg to false to allow pattern matching
    local found = haystack:reverse():find(needle:reverse(), nil, true)
    if found then
        return haystack:len() - needle:len() - found + 2 
    else
        return found
    end
end

print(findLast("my.string.here.", ".")) -- 15, because Lua strings are 1-indexed
print(findLast("my.string.here.", "here")) -- 11
print(findLast("my.string.here.", "there")) -- nil

如果你想要查找模式的最后一个实例,只需将最后一个参数更改为false(或删除它)。


2
你的例子对我返回了1 - Ryan Stein
抱歉,可能是我忘记了Lua字符串的工作方式。 - joews

3
这里提供一种使用LPeg的位置捕获的解决方案。
local lpeg      = require "lpeg"
local Cp, P     = lpeg.Cp, lpeg.P
local lpegmatch = lpeg.match

local cache = { }

local find_last = function (str, substr)
  if not (str and substr)
    or str == "" or substr == ""
  then
    return nil
  end
  local pat = cache [substr]
  if not pat then
    local p_substr   = P (substr)
    local last       = Cp() * p_substr * Cp() * (1 - p_substr)^0 * -1
    pat = (1 - last)^0 * last
    cache [substr] = pat
  end
  return lpegmatch (pat, str)
end
find_last()函数用于在字符串str中查找substr最后一次出现的位置,substr可以是任意长度的字符串。第一个返回值是substrstr中第一个字符的位置,第二个返回值是substr匹配的长度加上第一个返回值后的第一个字符的位置。

使用方法:

local tests = {
  A    = [[fooA]],                      --> 4, 5
  [""] = [[foo]],                       --> nil
  FOO  = [[]],                          --> nil
  K    = [[foo]],                       --> nil
  X    = [[X foo X bar X baz]],         --> 13, 14
  XX   = [[foo XX X XY bar XX baz X]],  --> 17, 19
  Y    = [[YYYYYYYYYYYYYYYYYY]],        --> 18, 19
  ZZZ  = [[ZZZZZZZZZZZZZZZZZZ]],        --> 14, 17
  --- Accepts patterns as well!
  [P"X" * lpeg.R"09"^1] = [[fooX42barXxbazX]], --> 4, 7
}

for substr, str in next, tests do
  print (">>", substr, str, "->", find_last (str, substr))
end

0

可以进行优化,但简单且能够完成工作。

function lastIndexOf(haystack, needle)
  local last_index = 0
  while haystack:sub(last_index+1, haystack:len()):find(needle) ~= nil do
    last_index = last_index + haystack:sub(last_index+1, haystack:len()):find(needle)
  end
  return last_index
end

local s = 'my.string.here.'
print(lastIndexOf(s, '%.')) -- 15

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接