【问题标题】:How to check whether grapheme is a letter?如何检查字形是否是字母?
【发布时间】:2016-04-13 13:03:05
【问题描述】:

我如何检查字形是否是字母(或经常在单​​词中使用的东西,如象形文字)?

查看 Elixir 的 String 文档后,我看到的唯一方法是检查 String.downcaseString.upcase 是否返回相同的字符串。如果他们这样做了,那么字形就不是用在单词中的东西了。

我就是这样做的,但肯定应该有更简单的方法吗?

defmodule Words do
  defp all_letters_uppercase?(string) do
    String.upcase(string) == string
  end

  defp all_letters_downcase?(string) do
    String.downcase(string) == string
  end

  defp contains_letter?(string) do
    not (all_letters_uppercase?(string) and all_letters_downcase?(string))
  end

  def single_grapheme?(string) do
    with graphemes = String.graphemes(string)
    do
      length(graphemes) == 1 and hd(graphemes) == string
    end
  end

  @doc """
  Check whether string is a single letter.
  """
  def letter?(string) do
    single_grapheme?(string) and contains_letter?(string)
  end
end

更新:我的代码不适用于日文字母

iex(35)> Words.letter?("グ")            
false

【问题讨论】:

    标签: unicode internationalization elixir


    【解决方案1】:

    您可以使用正则表达式来检查一些 unicode 功能,其中之一是\p{Letter},或简称为\p{L}。您可能想要添加 \p{Mark}*\p{M}* 以匹配多个以下组合变音符号。这将与String.graphemes/1 中的逻辑非常匹配。请务必在正则表达式之后添加 u 修饰符以启用这些 Unicode 功能。例如:

    iex> String.match?("グ", ~r/\A\p{L}\p{M}*\z/u)
    true
    

    另见http://erlang.org/doc/man/re.html,“Unicode 字符属性”部分和http://www.regular-expressions.info/unicode.html#grapheme

    【讨论】:

      【解决方案2】:

      这似乎工作正常:

      defmodule Words do
        def letter?(string) do
          Regex.match?(~r/^\p{L}$/fu, string)
        end
      end
      
      
      iex(51)> Words.letter?("a")
      true
      iex(52)> Words.letter?("é")
      true
      iex(53)> Words.letter?("グ")
      true
      iex(54)> Words.letter?("aa")
      false
      iex(55)> Words.letter?("1") 
      false
      iex(56)> Words.letter?("-")
      false
      iex(57)> Words.letter?("") 
      false
      iex(58)> Words.letter?(" ")
      false
      iex(59)> Words.letter?("éé")
      false
      iex(60)> Words.letter?("a ")
      false
      

      【讨论】:

      • Just my 2 ¢:如果您想匹配整个输入字符串,您还可以使用\A(字符串开头)和\z(字符串结尾)锚点。我发现^(行首)加上$(行尾)加上f(第一行)修饰语不太清楚地表达意图。
      • @PatrickOscity 很有趣,我什至不知道那些锚的存在。出于某种原因,每个人和他们的狗都使用^$
      • 这似乎与包含字母和组合字符的多码点字素不匹配,例如Words.letter?("g̈") #=> false 而您在问题中的代码返回 true。
      • 您也可以使用\p{L}\p{M}*来匹配任意数量的以下组合变音符号。
      • @CrabMan 组合标记可以任意组合形成字符和变音符号的任意组合。但是,许多常见的组合也可以作为预组合字符使用。或者,您只能使用String.normalize(input, :nfc) 匹配预先组合的字符,然后仅匹配\p{L}。但是我认为匹配组合标记也不会受到伤害。 String.graphemes/1 也将它们视为一个字符,因此您将与此逻辑非常匹配。还编辑了我的答案以包括组合标记。
      猜你喜欢
      • 1970-01-01
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-07
      • 2015-10-27
      • 2011-12-24
      • 2020-12-12
      • 1970-01-01
      相关资源
      最近更新 更多