2013-12-08 6 views
9

Desidero avere la possibilità di utilizzare un metodo lastIndexOf per le stringhe nel mio progetto Lua (Luvit). Sfortunatamente non esiste un tale metodo integrato e sono un po 'bloccato ora.Trova l'ultimo indice di un carattere in una stringa

in JavaScript sembra che:

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

Che problema stai cercando di risolvere esattamente? – lhf

+2

Penso che il modo più semplice sia usare 'string.find'' ('my.string.here.'): Find ("%. [^.] - $") '. ma è necessario sfuggire ai caratteri speciali (ad esempio '.',' * ',' + 'ecc.). Anche in Lua il risultato dovrebbe essere 15. – moteus

+0

@moteus bel suggerimento, ma volevo una soluzione comune (trovando anche l'indice per i numeri, per esempio) – Kosmetika

risposta

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

Nota che per trovare . è necessario sfuggire.

3

Per cercare l'ultima istanza di stringa needle in haystack:

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 

Se si desidera effettuare la ricerca per l'ultima istanza di un modello, invece, cambia l'ultimo argomento in find in false (o rimuovilo).

+2

Il tuo esempio restituisce '1' per me. –

+0

Scusa, a memoria - Devo aver dimenticato come funzionano le corde Lua. – joews

3

Se si hanno problemi di prestazioni, questo potrebbe essere un po 'più veloce se si utilizza Luvit che utilizza LuaJIT.

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. 

Tenete a mente che le stringhe Lua iniziano alle 1 invece di 0 come in JavaScript.

+0

trovato questo interessante post riguardante le prestazioni - https://neil.fraser.name/news/2009/12/25/, solo la curiosità ha fatto questa risposta fa fronte alle prestazioni - http://stackoverflow.com/a/20460403/2117550? – Kosmetika

+1

@ Kosmetika Interessante davvero.Non l'avevo mai visto prima, ma quello che ho scritto è molto vicino a 'lastIndexOfFind'. L'unica grande differenza è che la mia funzione restituisce 'nil' in opposizione a' -1', che è più stile Lua. Oh, e la mia funzione riprende dal secondo valore di ritorno di 'string.find', il che significa che salta alcune sottostringhe non necessarie ed è teoricamente più veloce. Credo che la risposta di @ lhf sia più performante su Lua semplice e meno su LuaJIT 2.1 a causa del fatto che 'string.match' non è ancora compilato, ma il modello fisso' string.find' è, ma dovrai eseguire i tuoi test per il tuo caso d'uso. –

3

Ecco una soluzione che utilizza l'acquisizione della posizione 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() trova l'ultima occorrenza di substr nella stringa str, dove substr può essere una stringa di qualsiasi lunghezza. Il primo valore di ritorno è la posizione del primo carattere di substr in str, il secondo valore di ritorno è la posizione del primo carattere seguente substr (cioè pari alla lunghezza della partita più la primo valore di ritorno).

Usage:

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

può essere ottimizzato, ma semplice e fa il lavoro.

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