Converte la stringa Elisir in intero o float


97

Devo convertire una stringa in un valore in virgola mobile o in un numero intero. Non esisteva un metodo come,

string_to_integer

Risposte:


153

36
Nota che questo restituirà una tupla (se ha successo) e non direttamente il numero intero. Se vuoi farlo, vedi @Szymon Jeż risposta conString.to_integer/1

6
C'è qualche motivo per usare Integer.parse/1sopra String.to_integer/1?
Ian Vaughan

10
@IanVaughan Integer.parse/1restituisce un :erroratomo se non ha successo. String.to_integer/1lancia un file (FunctionClauseError).
Jonathan Soifer

52

Oltre alle funzioni Integer.parse/1e Float.parse/1suggerite da José, puoi anche controllare String.to_integer/1e String.to_float/1.

Suggerimento: Vedi anche to_atom/1, to_char_list/1, to_existing_atom/1per altre conversioni.


27

Grazie gente in questa pagina, semplificando solo una risposta qui:

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

poiché convalida che l'intera stringa è stata analizzata (non solo un prefisso).


Questo genererà un errore se val non è puramente un numero intero. Ho aggiunto un caso al risultato per assicurarmi che la conversione fosse andata a buon fine. La seconda clausola può essere generica per rilevare: errore o una seconda stringa non vuota poiché non ti interessa molto se l'input era "x3" o "3x".
Sinc

14

Ci sono 4 funzioni per creare un numero dalla stringa

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

String.to_integerfunziona bene ma String.to_floatè più duro:

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

As String.to_floatpuò gestire solo float ben formattato, ad esempio:, 1.0not 1(integer). Ciò è stato documentato nel String.to_floatdocumento di

Restituisce un float la cui rappresentazione testuale è stringa.

stringa deve essere la rappresentazione di stringa di un float che include un punto decimale. Per analizzare una stringa senza punto decimale come float, è necessario utilizzare Float.parse / 1. Altrimenti, verrà sollevata un'eccezione ArgumentError.

Ma Float.parserestituisce una tupla di 2 elementi, non il numero che desideri, quindi metterlo nella pipeline non è "interessante":

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]

Usando elemper ottenere il primo elemento dalla tupla, rendilo più breve e più dolce:

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

Puoi convertirlo in un char_list e quindi utilizzare Erlang to_integer/1o to_float/1.

Per esempio

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

iex> myInt
23

Come usarlo nelle funzioni? La mia migliore soluzione è quella fn q -> {v, _} = Float.parse(q); v endche non mi piace. Mi piace usarlo Enum.map, ad esempio, list |> Enum.map(&String.to_float/1)ma string.to_float non funziona per i numeri interi?
Zhomart

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

1
IMO questa è la migliore risposta.
Marcin Adamczyk

Ho ricevuto questo errore: ** (UndefinedFunctionError) la funzione Decimal.new/1 non è definita (il modulo Decimal non è disponibile)
Daniel Cukier

4

Il problema con l'utilizzo Integer.parse/1è che analizzerà qualsiasi parte non numerica della stringa fintanto che si trova all'estremità della coda. Per esempio:

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

Allo stesso modo String.to_integer/1ha i seguenti risultati:

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

Invece, convalida prima la stringa.

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

L'espressione regolare potrebbe essere più semplice (ad esempio ^[0-9]*$) a seconda del tuo caso d'uso.


0

Se vuoi convertire una stringa in qualsiasi tipo numerico si trovi all'interno della stringa e rimuovere tutti gli altri caratteri, probabilmente è eccessivo, ma restituirà un float se è un float o un int se è un int o nil se la stringa non contiene un tipo numerico.

@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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.