Как можно сопоставлять шаблоны по тексту?

Предположим, что я хочу сопоставить шаблон с текстом. В частности, я хочу совпадение шаблонов в первой букве.

Например, как создать шаблон, который будет соответствовать "about" и "analog", но не "beta"?

Я пробовал это:

defmodule MatchStick do
    def doMatch([head | tail]) when head == "a" do 1 end
    def doMatch([head | tail]) do 0 end
end

res = MatchStick.doMatch("abcd");

Я также пробовал списки символов:

defmodule MatchStick do
    def doMatch([head | tail]) when head == 'a' do 1 end
    def doMatch([head | tail]) do 0 end
end

res = MatchStick.doMatch('abcd');

Ни один из них не работал. Каков правильный способ соответствия текста?

Ответы

Ответ 1

defmodule MatchStick do
  def doMatch("a" <> rest) do 1 end
  def doMatch(_) do 0 end
end

Вам нужно использовать оператор конкатенации строк, который отображается здесь

Пример:

iex> "he" <> rest = "hello"
"hello"
iex> rest
"llo"

Ответ 2

В Elixir строки в одинарных кавычках сильно отличаются от строк в двойных кавычках. Строки в одинарных кавычках в основном представляют собой списки целых чисел, где каждое целое число представляет символ. Поэтому они также называются списками символов. Они в основном используются для совместимости с Erlang, потому что так работают строки Erlang. Вы можете использовать строки в одинарных кавычках, как если бы вы использовали списки:

iex> hd('a')
97

iex> [97 | rest] = 'abcd'
'abcd'
iex> rest
'bcd'

iex> 'ab' ++ rest = 'abcd'
'abcd'
iex> rest
'cd'

Функция соответствия для строк в одинарных кавычках будет выглядеть следующим образом:

def match('a' ++ rest), do: 1
def match(_), do: 0

Elixir скроет список от вас и отобразит его в виде строки, когда все целые числа представляют действительные символы. Чтобы заставить Elixir показать вам внутреннее представление списка символов, вы можете вставить 0, что является недопустимым символом:

iex> string = 'abcd'
'abcd'
iex> string ++ [0]
[97, 98, 99, 100, 0]

Однако в Elixir обычно используются строки в двойных кавычках, поскольку они правильно обрабатывают UTF-8, с ними гораздо проще работать и они используются всеми внутренними модулями Elixir (например, полезным модулем String). Строки с двойными кавычками являются двоичными файлами, поэтому вы можете рассматривать их как любой другой двоичный тип:

iex> <<97, 98, 99, 100>>
"abcd"
iex> <<1256 :: utf8>>
"Ө"

iex> <<97>> <> rest = "abcd"
"abcd"
iex> rest
"bcd"

iex> "ab" <> rest = "abcd"
"abcd"
iex> rest
"cd"

Функция соответствия для строк в двойных кавычках будет выглядеть так:

def match("a" <> rest), do: 1
def match(_), do: 0

Elixir также скрывает внутреннее представление двоичных строк. Чтобы показать это, вы можете снова вставить 0:

iex> string = "abcd"
"abcd"
iex> string <> <<0>>
<<97, 98, 99, 100, 0>>

Наконец, для преобразования между строками с одинарными и двойными to_string вы можете использовать функции to_string и to_charlist:

iex> to_string('abcd')
"abcd"
iex> to_charlist("abcd")
'abcd'

Чтобы обнаружить их, вы можете использовать is_list и is_binary. Они также работают в пунктах охраны.

iex> is_list('abcd')
true
iex> is_binary('abcd')
false
iex> is_list("abcd")
false
iex> is_binary("abcd")
true

Например, чтобы сделать версию в двойных кавычках совместимой со строками в одинарных кавычках:

def match(str) when is_list(str), do: match(to_string(str))
def match("a" <> rest), do: 1
def match(_), do: 0

Ответ 3

Если вы хотите совместить шаблон с заголовком charlist, вам нужно сделать небольшое различие во втором фрагменте кода.

'a' на самом деле является charlist с одним элементом, поэтому сравнение с головой charlist всегда будет ложным. Charlist действительно представляет собой список целых значений:

iex> 'abcd' == [97, 98, 99, 100]
true

char a означает целое число 97. Вы можете получить целочисленный код символа в Elixir, указав его ?, поэтому:

iex> ?a == 97
true
iex> ?a == hd('a')
true

Итак, в вашем предложении охраны вам нужно сопоставить head == ?a или проще:

defmodule MatchStick do
    def doMatch([?a | _tail]), do: 1
    def doMatch(_), do: 0
end

Ответ 4

На всякий случай кому-то нужно. Если вам нужно сопоставить часть строки, которая находится в известной середине, и вы знаете ее длину, вы можете использовать двоичное сопоставление:

iex(1)> <<"https://", locale::binary-size(2), ".wikipedia.com" >> = "https://en.wikipedia.com" 
"https://en.wikipedia.com"
iex(2)> locale
"en"