2016-02-22 5 views

ответ

10

TL; DR: String.index/2 намеренно отсутствует, поскольку умнее альтернативы существуют. Очень часто String.split/2 решит основную проблему - и с лучшей эффективностью.

  • Я предполагаю, что мы говорим о строках UTF-8 здесь и ожидаем, что они будут иметь дело с символами, отличными от ASCII.

  • Эликсир поощряет быстрый код. Оказывается, проблемы, которые мы обычно пытаемся решить с помощью String.index/2, могут быть решены гораздо умнее, значительно улучшая производительность, не ухудшая читаемость кода.

  • Более разумное решение - использовать функции String.split/2 и/или другие аналогичные функции модуля String. String.split/2 работает на уровне байта, все еще правильно обрабатывая графемы. Это не может пойти не так, потому что оба аргумента - это строки! String.index/2 должен работать на уровне графем, медленно искажая всю строку.

  • По этой причине String.index/2 вряд ли будет добавлен к языку, если не появятся очень убедительные примеры использования, которые не могут быть решены с помощью существующих функций.

  • Смотрите также эликсир-лан-жильные дискуссии по этому вопросу: https://groups.google.com/forum/#!topic/elixir-lang-core/S0yrDxlJCss

  • На стороне записки, Elixir довольно уникален в своей зрелой поддержке Unicode. В то время как большинство языков работают на уровне кода (разговорные «персонажи»), Elixir работает с концепцией graphemes более высокого уровня. Графемы - это то, что пользователи воспринимают как один символ (скажем, более практическое понимание «персонажа»).Графемы могут содержать более одного кода (который, в свою очередь, может содержать более одного байта).

Наконец, если нам действительно нужно индекс:

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

Имеет String.split/2 устарела? Я вижу только split/1 и split/3 в самых последних документах. –

10

Я не думаю, что есть какая-нибудь Elixir обертка для этого, см #1119.

Вы можете позвонить :binary.match непосредственно до тех пор:

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

Возвращаемое значение представляет собой кортеж, содержащий индекс и продолжительность матча. Вы можете извлечь только индекс по трубопроводам в |> elem(0) или с помощью сопоставления с образцом.

Обратите внимание, что :binary.match возвращает :nomatch, если подстрока не найдена в строке.

4

Вы можете получить индекс байт с использованием :binary.match/3

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

Если вы хотите место в строке используйте:

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

Модуль документации String объясняет разницу между длиной байт и длиной строки ,

5

Вы можете использовать Regex.run/3 и передать его return: :index как вариант:

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

благодаря всем предыдущим ответам .. –

Смежные вопросы