Elm: String.toFloat doesn't work with comma only with point - what to do? - elm

I'm very new to elm and i want to do a simple mileage counter app.
If i get "1.2" (POINT) form input - String.toFloat returns in the OK branch with 1.2 as a number.
But if i get "1,2" (COMMA) form input, then String.toFloat returns in the Err branch with "You can't have words, only numbers!"
This pretty much works like a real time validator.
The code:
TypingInInput val ->
case String.toFloat val of
Ok success ->
{ model | inputValue = val, errorMessage = Nothing }
Err err ->
{ model | inputValue = val, errorMessage = Just "You can't have words, or spaces, only numbers!" }
.
Question: So how can i force String.toFloat of "1,2" to give me 1.2 the number?

Unfortunately the source for toFloat is hardcoded to only respect a dot as decimal separator. You can replace the comma with a dot in the string prior to passing it to toFloat as a workaround.
String.Extra.replace can be used for the simple string replacement.

The implementation of String.toFloat only supports a dot as a separator.
You should replace commas first before parsing the Float
Please see the example:
import Html exposing (text)
import String
import Regex
main =
"1,2"
|> Regex.replace Regex.All (Regex.regex ",") (\_ -> ".")
|> String.toFloat
|> toString
|> text -- 1.2
In JavaScript parseFloat doesn't support comma separator either.

Related

How to create a Kotlin Decimal Formatter

I would like to create a decimal formatter that would display up to 2 decimal digits, with a given separator.
For example with separator ","
input -> output
3.0 -> "3"
3.1 -> "3,1"
3.14 -> "3,14"
3.141 -> "3,14"
3.149 -> "3,15"
I would like to do this in Kotlin, I guess I must use DecimalFormat but don't understand how to do so. Could you please help me?
The code below was tested against all your examples and seemed to work well:
val locale = Locale("en", "UK")
val symbols = DecimalFormatSymbols(locale)
symbols.decimalSeparator = ','
val pattern = "#.##"
val decimalFormat = DecimalFormat(pattern, symbols)
val format = decimalFormat.format(3.14)
println(format) //3,14
To set a specific separator in your DecimalFormat, you can use setDecimalSeparator.
Pay attention to the pattern as # means:
A digit, leading zeroes are omitted
You can obviously change the locale to your fitting.
More information here.
You indeed might use java.text.NumberFormat to achieve your goal. The following should work is quite close to your example Swift code.
// you can change the separators by providing a Locale
val nf = java.text.NumberFormat
.getInstance(java.util.Locale.GERMAN)
nf.minimumFractionDigits = 0
nf.maximumFractionDigits = 2
// you may want to change the rounding mode
nf.roundingMode = java.math.RoundingMode.DOWN
println(nf.format(0)) // 0
println(nf.format(1)) // 1
println(nf.format(1.2)) // 1,2
println(nf.format(1.23)) // 1,23
println(nf.format(1.234)) // 1,23
println(nf.format(12.345)) // 12,34

How do I replace letters with numbers using the replace function in kotlin inside a lambda expression

mood = "leet"
modifier = { message ->
val regex = """(L|e|t)""".toRegex()
//Clueless about what to do after this
}
THIS IS WHAT I CAME UP WITH SO FAR, THE QUESTION IN THE BOOK BIG NERD RANCH KOTLIN EDITION 2 SAYS "leet (or 1337): The narrator will speak in leetspeak, replacing letters with numbers and symbols that look similar. For example, ‘L’ becomes ‘1’; ‘E’ becomes ‘3’; ‘T’ becomes ‘7’. (Hint: Take a look at String’s replace function. There is a version that accepts a lambda as the second parameter.)"
This is the function they're telling you to look at, specifically this one:
inline fun CharSequence.replace(
regex: Regex,
noinline transform: (MatchResult) -> CharSequence
): String
Returns a new string obtained by replacing each substring of this char sequence that matches the given regular expression with the result of the given function transform that takes MatchResult and returns a string to be used as a replacement for that match.
So the lambda you provide is a function that takes a MatchResult
and does something with it, and returns a CharSequence (which can be a one-character long String). The replace function calls that lambda for every match that regex makes.
You get the general idea of what you're supposed to do? You have two parts here - the thing that identifies parts of the input string to process, and the thing that takes those matches and changes them into something else. The result is the original string with those changes made. So you need to come up with a regex and a transform that work together.
Nobody (probably) is going to tell you the answer because the point is figuring it out for yourself, but if you have any questions about things like regexes people will be happy to help you out! And speaking of, this site is extremely useful (I just used it myself to check I knew what I was doing): https://regex101.com/
Here is the implementation as pointed by #cactustictacs :
5 -> {
mood = "leet"
val regex: Regex = """[LET]""".toRegex()
modifier = { message ->
message.uppercase().replace(regex) { m ->
when (m.value) {
"L" -> "1"
"E" -> "3"
"T" -> "7"
else -> ""
}
}
}
}
and here is the another method almost same but with minor change using regex.replace()
5 -> {
mood = "leet"
val regex: Regex = """[LET]""".toRegex()
modifier = { message ->
regex.replace(message.uppercase()){m ->
when (m.value) {
"L" -> "1"
"E" -> "3"
"T" -> "7"
else -> ""
}
}
}
}
You can use it in place of m to make it slightly more concise.

Format a string in Elm

I have a list of string and generate it to HTML dynamically with li tag. I want to assign that value to id attribute as well. But the problem is the string item has some special characters like :, ', é, ... I just want the output to include the number(0-9) and the alphabet (a-z) only.
// Input:
listStr = ["Pop & Suki", "PINK N' PROPER", "L'Oréal Paris"]
// Output:
result = ["pop_suki", "pink_n_proper", "loreal_paris"] ("loral_paris" is also good)
Currently, I've just lowercased and replace " " to _, but don't know how to eliminate special character.
Many thanks!
Instead of thinking of it as eliminating special characters, consider the permitted characters – you want just lower-case alphanumeric characters.
Elm provides Char.isAlphaNum to test for alphanumeric characters, and Char.toLower to transform a character to lower case. It also provides the higher function String.foldl which you can use to process a String one Char at a time.
So for each character:
check if it's alphanumeric
if it is, transform it to lower case
if not and it is a space, transform it to an underscore
else drop the character
Putting this together, we create a function that processes a character and appends it to the string processed so far, then apply that to all characters in the input string:
transformNextCharacter : Char -> String -> String
transformNextCharacter nextCharacter partialString =
if Char.isAlphaNum nextCharacter then
partialString ++ String.fromChar (Char.toLower nextCharacter)
else if nextCharacter == ' ' then
partialString ++ "_"
else
partialString
transformString : String -> String
transformString inputString =
String.foldl transformNextCharacter "" inputString
Online demo here.
Note: This answer simply drops special characters and thus produces "loral_paris" which is acceptable as per the OP.
The answer that was ticked is a lot more efficient than the code I have below. Nonetheless, I just want to add my code as an optional method.
Nonetheless, if you want to change accents to normal characters, you can install and use the elm-community/string-extra package. That one has the remove accent method.
This code below is inefficient as you keep on calling library function on the same string of which all of them would go through your string one char at a time.
Also, take note that when you remove the & in the first index you would have a double underscore. You would have to replace the double underscore with a single underscore.
import Html exposing (text)
import String
import List
import String.Extra
import Char
listStr = ["Pop & Suki", "PINK N' PROPER", "L'Oréal Paris"]
-- True if alpha or digit or space, otherwise, False.
isDigitAlphaSpace : Char -> Bool
isDigitAlphaSpace c =
if Char.isAlpha c || Char.isDigit c || c == ' ' then
True
else
False
main =
List.map (\x -> String.Extra.removeAccents x --Remove Accents first
|> String.filter isDigitAlphaSpace --Remove anything that not digit alpha or space
|> String.replace " " "_" --Replace space with _
|> String.replace "__" "_" --Replace double __ with _
|> String.toLower) listStr --Turn the string to lower
|> Debug.toString
|> Html.text

String to int conversion using toInt function

I am trying to convert a string to integer using String.toInt. However, when I want to bind the result to a variable and then do some simple math with it I get this error:
Function add is expecting the 2nd argument to be:
Int
But it is:
Result String Int
How can I just extract the integer part of the result?
Here's how to supply the conversion with a default value in case the parsing fails.
String.toInt "5" |> Result.toMaybe |> Maybe.withDefault 0
toInt can fail in parsing. You need to check it using a case statement:
case toInt str of
Err msg -> ... -- do something with the error message
Ok val -> ... -- val is an Int which you can add
More about Result here
The integer can also be pulled out using
Result.withDefault 0 (String.toInt "2")
You can read more about it here
According to the Elm String reference documentation, if you are extracting a number from some raw user input, you will typically want to use Result.withDefault to handle bad data in case parsing fails. You can chain this operation using pipes for cleaner code:
String.toInt "5" |> Result.withDefault 0
Maybe.withDefault 0 (String.toInt "42")
Use map:
answer = Result.map2 (+) (String.toInt "1") (String.toInt "2")
map2:
Apply a function to two results, if both results are Ok. If not, the
first argument which is an Err will propagate through.
to have the add result as a string
resultAsString r =
case r of
Err msg -> msg
Ok value -> toString value
resultAsString answer
to make things easier you can create an addStrings function:
addStrings : String -> String -> Result String Int
addStrings a b =
Result.map2 (+) (String.toInt a) (String.toInt b)
You can even get away with the Result type altogether:
addStrings : String -> String -> String
addStrings a b =
let
r =
Result.map2 (+) (String.toInt a) (String.toInt b)
in
case r of
Err msg ->
msg
Ok value ->
toString value
Testing
import Html exposing (Html, text)
main : Html msg
main =
text (addStrings "1" "2")
output 3
The withDefault method forces you to define a value that can be used for calculations but it is not always possible to establish a value that is significant for errors. Most often you need all the possible values, and default is not fit. Here I provide a result type check function you can use to decide if you use or not the converted value:
isErrorResult r =
case r of
Err msg ->
True
Ok value ->
False
You can use it like this:
r = String.toInt "20b"
if isErrorResult r then
-- not a valid Interger, abort or whatever
else
-- a good integer, extract it
a = Result.withDefault 0 r
-- and make good use of it
the default value (0 in this case) passed to withDefault is meaningless, because we made sure that r is not an Err.
You can do this as below.
---- Elm 0.19.0 ----------------------------------------------------------------
Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
--------------------------------------------------------------------------------
> parseInt string = String.toInt string
<function> : String -> Maybe Int
> resultParseInt string = \
| Result.fromMaybe ("error parsing string: " ++ string) (parseInt string)
<function> : String -> Result String Int
> resultParseInt "12"
Ok 12 : Result String Int
> resultParseInt "12ll"
Err ("error parsing string: 12ll") : Result String Int
>
I have changed guys answers a bit, since it appears to be of type Maybe
isErrorResult : String -> Bool
isErrorResult r =
case String.toInt r of
Nothing -> True
Just value -> False

How do you print a List in Elm?

How do I convert a value of type List to a String in Elm?
Basically I'm looking for a function with the signature a -> String or List -> String.
Example
Let's say I have a function intAverage:
intAverage l = case l of
[] -> 0
otherwise -> Debug.log (<<SHOW_FUNCTION>> l) (List.sum l // List.length l)
Here I want to inspect the list, in order to understand what's being passed to my function. Debug.log expects a String which makes me look for a function with the signature a -> String or List -> String but I have been unsuccessful in finding such a function in the Elm package docs.
Haskell has Debug.traceShow (which is simply an application of the function show on the first argument of Debug.trace) but I can't find the equivalent in Elm.
Edit: This is no longer true as of Elm version 0.19. See the other answer to this question.
The toString was what I was looking for, but couldn't find.
toString :: a -> String
I found it in the Basics-package: toString documentation
On Elm 0.19, it's been moved to Debug.toString:
For example:
> Debug.toString [1,2,3]
"[1,2,3]" : String