2016-02-22 14 views

risposta

10

TL; DR: String.index/2 è volutamente manca perché alternative più intelligenti esistono. Molto spesso String.split/2 risolverà il problema sottostante e, in un modo, prestazioni migliori.

  • presumo che stiamo parlando stringhe UTF-8 qui e aspettiamo di affrontare in modo pulito con caratteri non ASCII.

  • L'elisir incoraggia il codice veloce. Risulta che i problemi che in genere cerchiamo di risolvere con String.index/2 possono essere risolti in un modo molto più intelligente, migliorando notevolmente le prestazioni senza compromettere la leggibilità del codice.

  • La soluzione più intelligente è utilizzare String.split/2 e/o altre funzioni simili del modulo String. String.split/2 funziona a livello di byte pur gestendo correttamente i grafemi. Non può andare storto perché entrambi gli argomenti sono stringhe! String.index/2 dovrebbe lavorare su un livello di grafema, cercando lentamente tutta la stringa.

  • Per questo motivo è improbabile che il linguaggio String.index/2 venga aggiunto alla lingua a meno che non emergano casi di utilizzo molto interessanti che non possono essere risolti in modo pulito dalle funzioni esistenti.

  • Vedi anche la discussione elisir-lang-core su tale questione: https://groups.google.com/forum/#!topic/elixir-lang-core/S0yrDxlJCss

  • Su un lato nota, Elisir è abbastanza unico nel suo supporto Unicode maturo. Mentre la maggior parte delle lingue lavora su un livello codepoint (colloquialmente "personaggi"), Elixir funziona con un concetto di livello superiore di grafemi. I grafemi sono ciò che gli utenti percepiscono come un personaggio (diciamo che è una comprensione più pratica di un "personaggio").I grafemi possono contenere più di un punto di codice (che a sua volta può contenere più di un byte).

Infine, se abbiamo davvero bisogno l'indice:

case String.split("[email protected]", "domain", parts: 2) do 
    [left, _] -> String.length(left) 
    [_] -> nil 
end 
+1

Ha String.split/2 sono stati deprecati? Vedo solo split/1 e split/3 nei documenti più recenti. –

10

Non credo che ci sia alcun involucro elisir per questo, vedi #1119.

È possibile chiamare direttamente :binary.match fino ad allora:

iex(1)> :binary.match "[email protected]", "@" 
{9, 1} 
iex(2)> :binary.match "[email protected]", "domain" 
{10, 6} 

Il valore restituito è una tupla contenente l'indice e la lunghezza del match. È possibile estrarre solo l'indice piping in |> elem(0) o utilizzare la corrispondenza del modello.

Si noti che :binary.match restituisce :nomatch se la sottostringa non viene trovata nella stringa.

4

È possibile ottenere l'indice di byte utilizzando :binary.match/3

{index, length} = :binary.match("aéiou", "o")  
{4, 1} 

Se si desidera che la posizione nella stringa quindi utilizzare:

"aéiou" |> to_char_list() |> Enum.find_index(&(&1 == ?o)) 
3 

La documentazione del modulo String spiega la differenza tra la lunghezza di byte e la lunghezza della stringa .

5

È possibile utilizzare Regex.run/3 e passarlo return: :index come opzione:

iex(5)> [{start, len}] = Regex.run(~r/abc/, " abc ", return: :index) 
[{1, 3}] 
0
# index (as INSTR from basic...) 

... 
import IO, except: [inspect: 1] 
puts index "algopara ver", "ver" 

def index(mainstring, searchstring) do 
    tuple = (:binary.match mainstring, searchstring) 
    if tuple === :nomatch do 
     0 
    else 
     elem(tuple,0) 
    end 
end 
... 

9 
+0

grazie a tutte le precedenti risposte .. –

Problemi correlati