文字列を浮動小数点値または整数に変換する必要があります。次のような方法はありませんでした、
string_to_integer
Integer.parse/1
および Float.parse/1
。
Joséが提案したInteger.parse/1
およびFloat.parse/1
関数に加えて、String.to_integer/1
およびString.to_float/1
もチェックできます。
ヒント:他の変換については、to_atom/1
、to_char_list/1
、to_existing_atom/1
も参照してください。
このページの皆さんに感謝します。ここで答えを単純化します。
{intVal, ""} = Integer.parse(val)
プレフィックスだけでなく、文字列全体が解析されたことを検証するためです。
文字列から数値を作成する4つの関数があります
String.to_integer
はうまく機能しますが、String.to_float
はより厳しいです:
iex()> "1 2 3 10 100" |> String.split |> Enum.map(&String.to_integer/1)
[1, 2, 3, 10, 100]
iex()> "1.0 1 3 10 100" |> String.split |> Enum.map(&String.to_float/1)
** (ArgumentError) argument error
:erlang.binary_to_float("1")
(elixir) lib/enum.ex:1270: Enum."-map/2-lists^map/1-0-"/2
(elixir) lib/enum.ex:1270: Enum."-map/2-lists^map/1-0-"/2
String.to_float
は適切にフォーマットされたフロートのみを処理できるため、例:1.0
(整数)ではなく1
。 String.to_float
のドキュメントに記載されていました
テキスト表現が文字列であるfloatを返します。
stringは、小数点を含むfloatのストリング表現でなければなりません。小数点なしの文字列をfloatとして解析するには、Float.parse/1を使用する必要があります。そうでない場合、ArgumentErrorが発生します。
ただし、Float.parse
は、必要な数ではなく、2つの要素のTupleを返すため、パイプラインに入れることは「クール」ではありません。
iex()> "1.0 1 3 10 100" |> String.split \
|> Enum.map(fn n -> {v, _} = Float.parse(n); v end)
[1.0, 1.0, 3.0, 10.0, 100.0]
elem
を使用してTupleから最初の要素を取得すると、要素が短くなり、より美しくなります。
iex()> "1.0 1 3 10 100" |> String.split \
|> Enum.map(fn n -> Float.parse(n) |> elem(0) end)
[1.0, 1.0, 3.0, 10.0, 100.0]
これをchar_listに変換してから、Erlang to_integer/1
またはto_float/1
を使用できます。
例えば。
iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}
iex> myInt
23
Integer.parse/1
を使用する際の問題は、末尾にある限り、文字列の非数値部分を解析することです。例えば:
Integer.parse("01") # {1, ""}
Integer.parse("01.2") # {1, ".2"}
Integer.parse("0-1") # {0, "-1"}
Integer.parse("-01") # {-1, ""}
Integer.parse("x-01") # :error
Integer.parse("0-1x") # {0, "-1x"}
同様に、String.to_integer/1
の結果は次のとおりです。
String.to_integer("01") # 1
String.to_integer("01.2") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")
String.to_integer("0-1") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")
String.to_integer("-01") # -1
String.to_integer("x-01") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")
String.to_integer("0-1x") # ** (ArgumentError) argument error :erlang.binary_to_integer("01.2")
代わりに、最初に文字列を検証します。
re = Regex.compile!("^[+-]?[0-9]*\.?[0-9]*$")
Regex.match?(re, "01") # true
Regex.match?(re, "01.2") # true
Regex.match?(re, "0-1") # false
Regex.match?(re, "-01") # true
Regex.match?(re, "x-01") # false
Regex.match?(re, "0-1x") # false
ユースケースに応じて、正規表現はより単純になります(例:^[0-9]*$
)。
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float
文字列を文字列内の数値型に変換して他のすべての文字を削除したい場合、これはおそらくやり過ぎですが、文字列が含まれていない場合はfloatまたはint、intまたはnilの場合はfloatを返します数値型。
@spec string_to_numeric(binary()) :: float() | number() | nil
def string_to_numeric(val) when is_binary(val), do: _string_to_numeric(Regex.replace(~r{[^\d\.]}, val, ""))
defp _string_to_numeric(val) when is_binary(val), do: _string_to_numeric(Integer.parse(val), val)
defp _string_to_numeric(:error, _val), do: nil
defp _string_to_numeric({num, ""}, _val), do: num
defp _string_to_numeric({num, ".0"}, _val), do: num
defp _string_to_numeric({_num, _str}, val), do: elem(Float.parse(val), 0)