127

I need to convert a string to a floating point value or an integer. There was no method such as,

string_to_integer

9 Answers 9

196

Check Integer.parse/1 and Float.parse/1.

Sign up to request clarification or add additional context in comments.

4 Comments

Note that this will return a tuple (if successful) and not the integer directly. If you want to do that, see @Szymon Jeż answer with String.to_integer/1
Is there any reason to use Integer.parse/1 over String.to_integer/1?
@IanVaughan Integer.parse/1 returns a :error atom if unsuccessful. String.to_integer/1 throws a (FunctionClauseError).
To add to Jonathan's point, String.to_float("0") throws an error, while Float.parse("0") returns {0.0, ""}. This allowed me to use a single function when my string might not include a decimal point.
58

In addition to the Integer.parse/1 and Float.parse/1 functions which José suggested you may also check String.to_integer/1 and String.to_float/1.

Hint: See also to_atom/1,to_char_list/1,to_existing_atom/1for other conversions.

Comments

37

Thanks folks on this page, just simplifying an answer here:

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

as it validates that the entire string was parsed (not just a prefix).

1 Comment

This will throw an error if the val is not purely an integer. I added a case on the result to ensure the conversion was successful. The second clause can be generic to catch :error or a non-empty second string as you don't care much whether the input was "x3" or "3x".
27

There are 4 functions to create number from string

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

String.to_integer works nicely but String.to_float is tougher:

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 can only handle well-formatted float, e.g: 1.0, not 1 (integer). That was documented in String.to_float's doc

Returns a float whose text representation is string.

string must be the string representation of a float including a decimal point. In order to parse a string without decimal point as a float then Float.parse/1 should be used. Otherwise, an ArgumentError will be raised.

But Float.parse returns a tuple of 2 elements, not the number you want, so put it into pipeline is not "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]

Using elem to get first element from tuple make it shorter and sweeter:

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]

Comments

12

You can convert it to a char_list and then use the Erlang to_integer/1 or to_float/1.

E.g.

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

iex> myInt
23

1 Comment

How to use it in functions? My best solution is fn q -> {v, _} = Float.parse(q); v end which I don't like. I like to use it in Enum.map, e.g. list |> Enum.map(&String.to_float/1) but string.to_float doesn't work for integer numbers?
5

The problem with using Integer.parse/1 is that is will parse any non-numeric part of the string as long as it is in the tail end. For example:

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

Similarly String.to_integer/1 has the following results:

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

Instead, validate the string first.

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

The regular expression could be simpler (e.g. ^[0-9]*$) depending on your use case.

Comments

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

2 Comments

I got this error: ** (UndefinedFunctionError) function Decimal.new/1 is undefined (module Decimal is not available)
@DanielCukier Note that Decimal is a dependency that must be added to the project.
2

If you wanted to convert a string to whatever numeric type is within the string & remove all other characters, this is probably overkill, but will return a float if its a float or an int if its an int or nil if the string does not contain an numeric type.

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

Comments

0

You can use to_integer/1 and to_float/1

String.to_integer(numstr || "0")
String.to_float(numstr || "0.0")

1 Comment

Thank you for your interest in contributing to the Stack Overflow community. This question already has quite a few answers—including one that has been extensively validated by the community. Are you certain your approach hasn’t been given previously? Indeed, several mention these functions already. Given this, it would be useful to explain how your approach is different, under what circumstances your approach might be preferred, and/or why you think the previous answers aren’t sufficient. Can you kindly edit your answer to offer an explanation?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.