2013-12-08 163 views
9

我想要在我的Lua(Luvit)项目中为字符串使用lastIndexOf方法。不幸的是,没有内置的这种方法,现在我有点卡住了。查找字符串中字符的最后一个索引

在Javascript中,它看起来像:

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

你试图完全解决什么问题? – lhf

+2

我认为最简单的方法就是使用'string.find''('my.string.here。'):find(“%。[^。] - $”)''。但你需要转义特殊字符(例如'.','*','+'等)。也在Lua结果应该是15. – moteus

+0

@moteus很好的建议,但我想要通用的解决方案(例如找到数字索引) – Kosmetika

回答

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")) 

请注意,要找到.您需要将其转义。

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 

如果你想查找一个模式的最后一个实例,而不是,将最后一个参数更改为findfalse(或将其删除)。

+2

你的例子为我返回'1'。 –

+0

对不起,从记忆 - 我一定忘记了Lua字符串是如何工作的。 – joews

3

如果您有性能方面的担忧,那么如果您使用使用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代替0开始为JavaScript中。

+0

发现这个有趣的职位关于性能 - https://neil.fraser.name/news/2009/12/25/,只是好奇心这个答案应对性能 - http://stackoverflow.com/a/20460403/2117550? – Kosmetika

+1

@Kosmetika确实很有趣。我之前没有看到它,但是我写的非常接近'lastIndexOfFind'。唯一的区别是我的函数返回'nil'而不是'-1',这是更多的Lua风格。哦,我的函数从'string.find'的第二个返回值中提取出来,这意味着它会跳过一些不必要的子字符串,理论上更快。我相信@ lhf的答案在纯Lua上的表现更好,而在LuaJIT 2.1中则更少,因为string.match没有被编译,但固定模式是string.find,但是你必须为你的测试执行自己的测试用例。 –

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()发现SUBSTR的最后一次出现的串 STR,其中SUBSTR可以是任何长度的字符串英寸 第一个返回值是 SUBSTR的第一个字符的在STR的位置时,第二返回值是 第一个字符的以下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 
相关问题