如何在文本上进行模式匹配?

时间:2014-09-17 17:24:56

标签: elixir

让我们说我希望模式匹配文本。具体来说,我想在第一个字母上进行模式匹配。

例如,如何创建一个匹配" about"和"模拟"但不是" 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');

都没有奏效。匹配文本的正确方法是什么?

4 个答案:

答案 0 :(得分:32)

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

您需要使用字符串连接运算符here

示例:

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

答案 1 :(得分:16)

在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_stringto_char_list

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

要检测它们,您可以使用is_listis_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

答案 2 :(得分:0)

如果你想在一个charlist的头部进行模式匹配,你需要在你的第二个代码片段中略微区别。

'a'实际上是一个包含一个元素的charlist,因此与charlist的头部进行比较将始终为false。 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

答案 3 :(得分:0)

以防万一有人需要。如果您需要匹配已知中间部分的字符串,并且知道其长度,则可以使用二进制匹配:

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