Elixir dizesini tam sayıya veya şamandıraya dönüştür


98

Bir dizeyi kayan nokta değerine veya tam sayıya dönüştürmem gerekiyor. Gibi bir yöntem yoktu,

string_to_integer

Yanıtlar:


154

Kontrol edin Integer.parse/1ve Float.parse/1.


37
Bunun doğrudan bir tamsayı değil, bir demet (başarılıysa) döndüreceğini unutmayın. Bunu yapmak istiyorsanız, bkz. @Szymon Jeż ile cevaplayınString.to_integer/1

6
Kullanmak için herhangi bir neden var mı Integer.parse/1üzerinde String.to_integer/1?
Ian Vaughan

10
@IanVaughan başarısız olursa Integer.parse/1bir :erroratom döndürür . String.to_integer/1bir atar (FunctionClauseError).
Jonathan Soifer

52

Ek olarak Integer.parse/1ve Float.parse/1José de kontrol edebilir önerdi fonksiyonları String.to_integer/1ve String.to_float/1.

İpucu: Ayrıca bkz to_atom/1, to_char_list/1, to_existing_atom/1diğer dönüşümler için.


28

Bu sayfadaki teşekkürler millet, sadece burada bir cevabı basitleştirerek:

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

tüm dizenin ayrıştırıldığını doğrular (yalnızca bir önek değil).


Val tamamen bir tamsayı değilse, bu bir hata verecektir. Dönüşümün başarılı olmasını sağlamak için sonuca bir vaka ekledim. İkinci cümle, girdinin "x3" veya "3x" olup olmadığını pek umursamadığınız için: hatayı veya boş olmayan bir ikinci dizeyi yakalamak için genel olabilir.
Sincap

14

Dizeden numara oluşturmak için 4 işlev vardır

  • String.to_integer, String.to_float
  • Tamsayı.parse, Float.parse

String.to_integergüzel çalışıyor ama String.to_floatdaha zor:

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_float: Sadece örn iyi biçimlendirilmiş float, işleyebilir 1.0, değil 1(tam sayı). Yani belgelenmiştir String.to_floatbireyin doc

Metin gösterimi dize olan bir kayan nokta döndürür.

dize, ondalık nokta içeren bir kayan noktanın dize temsili olmalıdır. Ondalık noktası olmayan bir dizeyi float olarak ayrıştırmak için Float.parse / 1 kullanılmalıdır. Aksi takdirde, bir ArgumentError ortaya çıkar.

Ancak Float.parseistediğiniz sayıyı değil, 2 öğeden oluşan bir demet döndürür, bu nedenle ardışık düzene koymak "harika" değildir:

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]

elemTuple'dan ilk öğeyi almak için kullanmak onu daha kısa ve daha tatlı hale getirir:

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

Bunu bir char_list'e dönüştürebilir ve ardından Erlang to_integer/1veya to_float/1.

Örneğin

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

iex> myInt
23

İşlevlerde nasıl kullanılır? En iyi çözümüm, fn q -> {v, _} = Float.parse(q); v endsevmediğim şey. Bunu içinde kullanmayı seviyorum Enum.map, örneğin, list |> Enum.map(&String.to_float/1)ancak string.to_float tam sayılar için çalışmıyor mu?
Zhomart

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

1
IMO bu en iyi cevaptır.
Marcin Adamczyk

Bu hatayı aldım: ** (UndefinedFunctionError) işlevi Decimal.new/1 tanımsız (Decimal modülü mevcut değil)
Daniel Cukier

4

Kullanmanın sorunu Integer.parse/1, kuyruk ucunda olduğu sürece dizenin sayısal olmayan herhangi bir parçasını ayrıştıracak olmasıdır. Örneğin:

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

Benzer şekilde String.to_integer/1aşağıdaki sonuçlara sahiptir:

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

Bunun yerine, önce dizeyi doğrulayın.

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

Normal ifade ^[0-9]*$, kullanım durumunuza bağlı olarak daha basit olabilir (örneğin ).


0

Bir dizeyi dizenin içindeki sayısal türe dönüştürmek ve diğer tüm karakterleri kaldırmak istiyorsanız, bu muhtemelen aşırıdır, ancak bir float ise bir float veya dizede yoksa bir int veya nil ise bir int döndürür. sayısal bir tür.

@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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.