Konvertieren Sie die Elixir-Zeichenfolge in eine Ganzzahl oder einen Gleitkommawert


97

Ich muss eine Zeichenfolge in einen Gleitkommawert oder eine Ganzzahl konvertieren. Es gab keine Methode wie:

string_to_integer

Antworten:


153

Überprüfen Sie Integer.parse/1und Float.parse/1.


36
Beachten Sie, dass dies ein Tupel (falls erfolgreich) und nicht die Ganzzahl direkt zurückgibt. Wenn Sie das tun möchten, sehen Sie @Szymon Jeż Antwort mitString.to_integer/1

6
Gibt es einen Grund zu verwenden , Integer.parse/1über String.to_integer/1?
Ian Vaughan

10
@IanVaughan Integer.parse/1gibt ein :errorAtom zurück, wenn dies nicht erfolgreich ist. String.to_integer/1wirft a (FunctionClauseError).
Jonathan Soifer

52

Zusätzlich zu den Integer.parse/1und Float.parse/1Funktionen, die José vorgeschlagen hat, können Sie auch String.to_integer/1und überprüfen String.to_float/1.

Hinweis: Siehe auch to_atom/1, to_char_list/1, to_existing_atom/1für andere Konvertierungen.


27

Vielen Dank Leute auf dieser Seite, die hier nur eine Antwort vereinfachen:

{intVal, ""} = Integer.parse(val)

da es bestätigt, dass die gesamte Zeichenfolge analysiert wurde (nicht nur ein Präfix).


Dies löst einen Fehler aus, wenn der Wert keine reine Ganzzahl ist. Ich habe dem Ergebnis einen Fall hinzugefügt, um sicherzustellen, dass die Konvertierung erfolgreich war. Die zweite Klausel kann generisch sein, um zu fangen: Fehler oder eine nicht leere zweite Zeichenfolge, da es Ihnen egal ist, ob die Eingabe "x3" oder "3x" war.
Seit dem

14

Es gibt 4 Funktionen zum Erstellen einer Nummer aus einer Zeichenfolge

  • String.to_integer, String.to_float
  • Integer.parse, Float.parse

String.to_integerfunktioniert gut, String.to_floatist aber härter:

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

Da String.to_floatkann nur gut formatiertes Float verarbeitet werden, zB: 1.0nicht 1(Integer). Das wurde in String.to_float's doc dokumentiert

Gibt einen Float zurück, dessen Textdarstellung eine Zeichenfolge ist.

Zeichenfolge muss die Zeichenfolgendarstellung eines Gleitkommas einschließlich eines Dezimalpunkts sein. Um eine Zeichenfolge ohne Dezimalpunkt als Gleitkomma zu analysieren, sollte Float.parse / 1 verwendet werden. Andernfalls wird ein ArgumentError ausgelöst.

Aber Float.parsegibt ein Tupel von zwei Elementen, nicht die Zahl , die Sie wollen, es so in Pipeline setzen ist nicht „cool“:

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]

Verwenden Sie elem, um das erste Element aus dem Tupel zu erhalten, und machen Sie es kürzer und süßer:

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]

11

Sie können es in eine char_list konvertieren und dann Erlang to_integer/1oder verwenden to_float/1.

Z.B

iex> {myInt, _} = :string.to_integer(to_char_list("23"))
{23, []}

iex> myInt
23

Wie benutzt man es in Funktionen? Meine beste Lösung ist fn q -> {v, _} = Float.parse(q); v enddie, die ich nicht mag. Ich benutze es gerne in Enum.map, zB list |> Enum.map(&String.to_float/1)aber string.to_float funktioniert nicht für Ganzzahlen?
Zhomart

5
Decimal.new("1") |> Decimal.to_integer
Decimal.new("1.0") |> Decimal.to_float

1
IMO das ist die beste Antwort.
Marcin Adamczyk

Ich habe diesen Fehler erhalten: ** (UndefinedFunctionError) -Funktion Decimal.new/1 ist undefiniert (Modul Decimal ist nicht verfügbar)
Daniel Cukier

4

Das Problem bei der Verwendung Integer.parse/1besteht darin, dass alle nicht numerischen Teile der Zeichenfolge analysiert werden, solange sie sich am hinteren Ende befinden. Beispielsweise:

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"}

Ebenso String.to_integer/1hat die folgenden Ergebnisse:

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")

Überprüfen Sie stattdessen zuerst die Zeichenfolge.

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

Der reguläre Ausdruck kann ^[0-9]*$je nach Anwendungsfall einfacher sein (z. B. ).


0

Wenn Sie eine Zeichenfolge in einen beliebigen numerischen Typ innerhalb der Zeichenfolge konvertieren und alle anderen Zeichen entfernen möchten, ist dies wahrscheinlich ein Overkill, gibt jedoch einen Gleitkommawert zurück, wenn es sich um einen Gleitkommawert handelt, oder einen Int, wenn es sich um einen Int handelt, oder einen Nullwert, wenn der String nicht enthält ein numerischer Typ.

@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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.