I know that there's a lot of questions about converting string to float/number/decimal... but my case is quite different cause I need to convert the string number (representing a dollar value) but I must keep the cents in this conversion, here is my case.
I receive this values
"96,26"
"1.296,26"
And I expect to convert to this follow:
96.26
1296.26
If I try to use clojure.edn it escape cents
(edn/read-string "1.296,26")
=> 1.296
(edn/read-string "96,26")
=> 96
If I try to use another approach like bugdec I get NumberFormatException
I know that we can do some string replace but it looks like a big work around, like this:
(-> "1.296,87"
(clojure.string/replace #"\." "")
(clojure.string/replace #"," ".")
(edn/read-string))
what you can do, is to use java's formatting facilities:
(defn read-num [s]
(let [format (java.text.NumberFormat/getNumberInstance java.util.Locale/GERMANY)]
(.parse format s)))
user> (read-num "1.296,26")
;;=> 1296.26
user> (read-num "96,26")
;;=> 96.26
Just use straight Java interop:
(let [nf (java.text.NumberFormat/getInstance java.util.Locale/FRENCH)]
(.parse nf "12,6")) => 12.6
See the Oracle docs: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/text/NumberFormat.html
and this posting: https://www.baeldung.com/java-decimalformat
You can also get a BigDecimal to avoid any rounding errors. See https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/text/DecimalFormat.html#%3Cinit%3E(java.lang.String,java.text.DecimalFormatSymbols)
(let [nf (DecimalFormat. "" (DecimalFormatSymbols. Locale/ITALIAN))
>> (.setParseBigDecimal nf true)
result (.parse nf "123.45,9")]
result => <#java.math.BigDecimal 12345.9M>
Related
I would like to format a 'numeric' string as a 'string number' in Clojure. This is the format mask:
"#,###,###,##0.00"
Given the string "9999.99" I would expect to receive back "9,999.99".
How would I do this in Clojure without resorting to writing a converter function i.e. using format or something similar?
It appears that in your problem domain the disadvantages and limitations of binary-base floating point (e.g. IEEE-754) are causing you some difficulty. Perhaps you should consider taking advantage of the BigDecimal support already built in to Clojure. In Clojure, the difference between a BigDecimal constant and a floating point constant is a single character; e.g. 1.2 is a Double, while 1.2M is a BigDecimal. The bigdec function can be used to convert things to BigDecimal on the fly. For example,
(format "%,.2f" (bigdec "9999999999999999.12"))
produces
"9,999,999,999,999,999.12"
as expected. Arithmetic functions such as *, +, -, and / also work as expected.
However, this doesn't solve your basic problem. If your format string doesn't follow Java/Clojure format string conventions you'll have to write a converter function.
Best of luck.
You can use , in a format specifier:
(format "%,.2f" (float (clojure.edn/read-string "9999")))
=> "9,999.00"
(format "%,.2f" (Double/parseDouble "9999.126"))
=> "9,999.13"
Update to include bigdec example:
(format "%,.2f" (bigdec "9999999999999999.12"))
=> "9,999,999,999,999,999.12"
You can do this using NumberFormat. I also like the other answer (see the Java 10 Formatter docs for details):
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:import [java.text NumberFormat]
[java.util Locale]))
(dotest
(let [value (Double/valueOf "1234567.89")
nf (NumberFormat/getNumberInstance (Locale/US))
s1a (.format nf (.doubleValue value))
s1b (format "%,05.2f" value)]
(spyx s1a)
(spyx s1b))
s1a => "1,234,567.89"
s1b => "1,234,567.89"
(let [value (Double/valueOf "1.2")
nf (NumberFormat/getNumberInstance (Locale/US))
s1a (.format nf (.doubleValue value))
s1b (format "%,05.2f" value)]
(spyx s1a)
(spyx s1b)))
s1a => "1.2"
s1b => "01.20"
Update
Here is how to do it for BigDecimal, using first Java interop and then a built-in Clojure function bigdec:
(format "%,05.2f" (BigDecimal. "9999999999999999.12")) => "9,999,999,999,999,999.12"
(format "%,05.2f" (bigdec "9999999999999999.12")) => "9,999,999,999,999,999.12"
Question from a total newbie with Clojure. Task is pretty simple, but I'm having hard time finding the best way to do this - I need to set up input, where user could give me a list (user should determine how long) of natural numbers and the program should just return a sum of these numbers.
Maybe this is totally wrong already:
(defn inputlist[naturallist]
(println "Enter list of natural numbers:")
(let[naturallist(read-line)] ))
Here is one way of doing it:
> lein new app demo
> cd demo
Edit the project.clj and src/demo/core.clj so they look as follows:
> cat project.clj
(defproject demo "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0"]
[org.clojure/tools.reader "1.1.3.1"] ]
:main ^:skip-aot demo.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
> cat src/demo/core.clj
(ns demo.core
(:require
[clojure.tools.reader.edn :as edn]
[clojure.string :as str] ))
(defn -main []
(println "enter numbers")
(let [input-line (read-line)
num-strs (str/split input-line #"\s+")
nums (mapv edn/read-string num-strs)
result (apply + nums) ]
(println "result=" result)))
with result
> lein run
enter numbers
1 2 3 <= you type this, then <enter>
input-line => "1 2 3"
num-strs => ["1" "2" "3"]
nums => [1 2 3]
result => 6
You may wish to start looking at some beginner books as well:
Brave Clojure
Living Clojure
Programming Clojure
The Clojure CheatSheet
The quickest way to do this I can think of is
#(apply + (map #(Integer/parseInt %) (re-seq #"\d+" (read-line))))
This defines an anonymous function which:
(read-line) - reads a line of text, hopefully containing numbers separated by non-numeric characters. So you type in something like "123 456 789"
(re-seq #"\d+" ...) - uses the regular expression \d+ to search for strings of consecutive digits. Each string of consecutive digits is added to a sequence, which is subsequently returned. So, for example, if you type in 123, 456, 789 the re-seq function will return the sequence '("123" "456" "789").
(map #(Integer/parseInt %) ...) - invokes the anonymous function #(Integer/parseInt %) for each element in the list returned by the re-seq invocation, creating another list of the results. So if the input is '("123" "456" "789") the output will be '(123 456 789).
(apply + ...) - applies the + function to the list of numbers, summing them up, and returns the sum.
Et voila! The end result is, you type in a string of numbers, separated by non-numeric characters, you get back the sum of those numbers. If you want to be a little neater, promote code re-use, and in general make this a bit more useful you could break this up into separate functions:
(defn parse-string-list [s]
(re-seq #"\d+" s))
(defn convert-seq-of-int-strings [ss]
(map #(Integer/parseInt %) ss))
(defn sum-numbers-in-seq [ss]
(apply + ss))
Invoking this in a Lisp-y way would look something like
(sum-numbers-in-seq (convert-seq-of-int-strings (parse-string-list (read-line))))
or, in a more Clojure-y way
(-> (read-line)
(parse-string-list)
(convert-seq-of-int-strings)
(sum-numbers-in-seq))
Best of luck.
Welcome to Clojure—and StackOverflow!
Here's how to do it:
(defn input-numbers-and-sum []
(print "Enter list of natural numbers: ")
(flush)
(->> (clojure.string/split (read-line) #"\s+")
(map #(Integer/parseInt %))
(reduce +)))
Here's how it works:
Calling print rather than println avoids printing a newline character at the end of the line. This way, the user's input will appear on the same line as your prompt.
Since there was no newline, you have to call flush to force the output buffer containing the prompt to be printed.
split splits what the user typed into a sequence of strings, divided where a regular expression matches. You have to say clojure.string/split rather than just split because split is not in Clojure's core library. clojure.string/ specifies the library. #"\s+" is a regular expression that matches any number of consecutive whitespace characters. So, if your user types " 6 82 -15 ", split will return ["6" "82" "-15"].
map calls the standard Java library function Integer.parseInt on each of those strings. Integer/parseInt is Clojure's Java interop syntax for calling a static method of a Java class. The #(...) is terse syntax that defines an anonymous function; the % is the argument passed to that function. So, given the sequence of strings above, this call to map will return a sequence of integers: [6 82 -15].
reduce calls the + function repeatedly on each element of the sequence of integers, passing the sum so far as an argument along with the next integer. map and reduce actually take three arguments; the next paragraph tells how the third paragraph gets filled in.
->> is the "thread-last macro". It rewrites the code inside it, to pass the output of each expression but the last as the last argument of the following expression. The result is:(reduce + (map #(Integer/parseInt %) (clojure.string/split (read-line) #"\s+")))Most people find the version with ->> much easier to read.
That might seem like a lot to do something very simple, but it's actually bread and butter once you're used to Clojure. Clojure is designed to make things easy to combine; map, reduce, and ->> are especially useful tools for hooking other functions together.
I've included links to the documentation. Those are worth a look; many contain typical examples of use.
There are other ways to parse numbers, of course, some of which are shown in the answers to this question. What I've written above is an "idiomatic" way to do it. Learn that, and you'll know a lot of the everyday, must-know techniques for programming in Clojure.
Yep, readline is the correct way to do it.
But each element from readlines is essentially an instance of java.lang.Character , and since you want the sum, you'd prefer to convert them to integer before summing the elements of list.
(defn input-list
[]
(print "Enter list of natural numbers")
(let [nums (read-line)]
(reduce + (map #(Integer/parseInt %) (clojure.string/split nums #"\s+")))
This might not be the most idiomatic way to do it, but feel free to tweak it.
Also, please do clean up on your variable/function names.
Edit : (Integer/parseInt %) might cause an error if used directly since the input is an instance of characters, not string. So we can use clojure.string/split to convert user input to a sequence of strings, and use Integer/parseInt % for conversion.
In fact, a more readable version can be written using thread-first macros :
(defn input-list []
(print "Enter list of natural numbers: ")
(->> (clojure.string/split (read-line) #"\s+")
(map #(Integer/parseInt %))
(reduce +)))
This is a more clojurey way to do it.
If you don't care about negative scenarios (wrong input, syntax issues), the quickest solution would be to evaluate the user's input putting it into parens:
(defn sum-ints []
(let [input (read-line)
ints (read-string (str "(" input ")"))]
(reduce + 0 ints)))
Usage:
user=> (sum-ints)
1 2 3 4 5
15
The read-string function evaluates an text expression (1 2 3 4 5) in that case. Since numeral literals turn into numbers, the result will be just a list of numbers.
I have the following line in my code:
(spit path (prn-str job-data))
It does it's work well execpt for one thing, every item in the list are put between double-quotes...
( ":a" ":b" ":a" )
the expected result that I'd like to have
( :a :b :a )
How to get the expected result?
Thanks in advance!
What's happening
The issue isn't that the items are being put in double quotes per se but that they're strings (as opposed to the keywords you're expecting).
prn-str, which is ultimately based on pr, prints objects "in a way that objects can be read by the reader". This means strings are printed in double-quotes - otherwise the reader wouldn't be able to tell strings from symbols, or read strings with whitespace in them. See here for more information on Clojure's reader.
println and print, on the other hand, are intended to "produce output for human consumption" and do not put strings in double-quotes. This is why you're seeing the difference in output between prn-str and println.
You can verify this with class. If you try (-> job-data first class) the answer will be either java.lang.String or clojure.lang.Keyword.
Here are some examples demonstrating the different behaviors of the printing functions when used with keywords and strings:
(def str-job-data '(":a" ":b" ":c"))
(def key-job-data '(:a :b :c))
;; `println` prints both keywords and strings without quotes
(with-out-str (println str-job-data)) ;=> "(:a :b :c)\n"
(with-out-str (println key-job-data)) ;=> "(:a :b :c)\n"
;; `prn-str` prints the strings in quotes but the keywords without quotes
(prn-str str-job-data) ;=> "(\":a\" \":b\" \":c\")\n"
(prn-str key-job-data) ;=> "(:a :b :c)\n"
How to change it
Now for possible solutions. If you were expecting job-data to contain keywords then the right fix is most likely to modify job-data. However, I can't offer much guidance here without knowing more about how job-data is produced.
If for some reason you can't modify job-data (for instance, if it's produced by code you don't control) and you want to write keywords wherever it contains keyword-like strings then something like #maxthoursie's suggestion is probably your best bet. (You could hypothetically just switch to print or println but that could have undesirable effects on how other objects are printed).
(defn keyword-string->keyword [s]
(keyword (subs s 1)))
(spit path (prn-str (map keyword-string->keyword job-data)))
If job-data might contain objects other than keyword-like strings you could apply the function only when appropriate.
(defn convert-job-data [obj]
(if (and (string? obj)
(= (.charAt obj 0) \:))
(keyword-string->keyword obj)
obj))
(spit path (prn-str (map convert-job-data job-data)))
Of course, if the file you're writing is for human consumption anyway and all this business about the reader is irrelevant you could trivially make your own println-str:
(defn println-str [& more]
(with-out-str (apply println more)))
(spit path (println-str job-data))
I'm guessing job-data is not what you expect it to be.
user=> (prn-str '(:a :b :c))
"(:a :b :c)\n"
If you do have a list with strings that looks like keywords, and you would like to convert it to keywords, you could use something like
(map (comp keyword #(subs % 1)) '(":a" ":b" ":c"))
Which skips the : of each element, and then converts it to a keyword.
user=> (prn-str (map (comp keyword #(subs % 1)) '(":a" ":b" ":c")))
"(:a :b :c)\n"
Iam new to clojure and need some help to get a value out of a lazy sequence.
You can have a look at my full data structure here: http://pastebin.com/ynLJaLaP
What I need is the content of the title:
{: _content AlbumTitel2}
I managed to get a list of all _content values:
(def albumtitle (map #(str (get % :title)) photosets))
(println albumtitle)
and the result is:
({:_content AlbumTitel2} {:_content test} {:_content AlbumTitel} {:_content album123} {:_content speciale} {:_content neues B5 Album} {:_content Album Nr 2})
But how can I get the value of every :_content?
Any help would be appreciated!
Thanks!
You could simply do this
(map (comp :_content :title) photosets)
Keywords work as functions, so the composition with comp will first retrieve the :title value of each photoset and then further retrieve the :_content value of that value.
Alternatively this could be written as
(map #(get-in % [:title :_content]) photosets)
A semi alternative solution is to do
(->> data
(map :title)
(map :_content))
This take advances of the fact that keywords are functions and the so called thread last macro. What it does is injecting the result of the first expression in as the last argument of the second etc..
The above code gets converted to
(map :_content (map :title data))
Clearly not as readable, and not easy to expand later either.
PS I asume something went wrong when the data was pasted to the web, because:
{: _content AlbumTitel2}
Is not Clojure syntax, this however is:
{:_content "AlbumTitel2"}
No the whitespace after :, and "" around text. Just in case you might want to paste some Clojure some other time.
I've been using java to parse numbers, e.g.
(. Integer parseInt numberString)
Is there a more clojuriffic way that would handle both integers and floats, and return clojure numbers? I'm not especially worried about performance here, I just want to process a bunch of white space delimited numbers in a file and do something with them, in the most straightforward way possible.
So a file might have lines like:
5 10 0.0002
4 12 0.003
And I'd like to be able to transform the lines into vectors of numbers.
You can use the edn reader to parse numbers. This has the benefit of giving you floats or Bignums when needed, too.
user> (require '[clojure.edn :as edn])
nil
user> (edn/read-string "0.002")
0.0020
If you want one huge vector of numbers, you could cheat and do this:
user> (let [input "5 10 0.002\n4 12 0.003"]
(read-string (str "[" input "]")))
[5 10 0.0020 4 12 0.0030]
Kind of hacky though. Or there's re-seq:
user> (let [input "5 10 0.002\n4 12 0.003"]
(map read-string (re-seq #"[\d.]+" input)))
(5 10 0.0020 4 12 0.0030)
Or one vector per line:
user> (let [input "5 10 0.002\n4 12 0.003"]
(for [line (line-seq (java.io.BufferedReader.
(java.io.StringReader. input)))]
(vec (map read-string (re-seq #"[\d.]+" line)))))
([5 10 0.0020] [4 12 0.0030])
I'm sure there are other ways.
If you want to be safer, you can use Float/parseFloat
user=> (map #(Float/parseFloat (% 0)) (re-seq #"\d+(\.\d+)?" "1 2.2 3.5"))
(1.0 2.2 3.5)
user=>
Not sure if this is "the easiest way", but I thought it was kind of fun, so... With a reflection hack, you can access just the number-reading part of Clojure's Reader:
(let [m (.getDeclaredMethod clojure.lang.LispReader
"matchNumber"
(into-array [String]))]
(.setAccessible m true)
(defn parse-number [s]
(.invoke m clojure.lang.LispReader (into-array [s]))))
Then use like so:
user> (parse-number "123")
123
user> (parse-number "123.5")
123.5
user> (parse-number "123/2")
123/2
user> (class (parse-number "123"))
java.lang.Integer
user> (class (parse-number "123.5"))
java.lang.Double
user> (class (parse-number "123/2"))
clojure.lang.Ratio
user> (class (parse-number "123123451451245"))
java.lang.Long
user> (class (parse-number "123123451451245123514236146"))
java.math.BigInteger
user> (parse-number "0x12312345145124")
5120577133367588
user> (parse-number "12312345142as36146") ; note the "as" in the middle
nil
Notice how this does not throw the usual NumberFormatException if something goes wrong; you could add a check for nil and throw it yourself if you want.
As for performance, let's have an unscientific microbenchmark (both functions have been "warmed up"; initial runs were slower as usual):
user> (time (dotimes [_ 10000] (parse-number "1234123512435")))
"Elapsed time: 564.58196 msecs"
nil
user> (time (dotimes [_ 10000] (read-string "1234123512435")))
"Elapsed time: 561.425967 msecs"
nil
The obvious disclaimer: clojure.lang.LispReader.matchNumber is a private static method of clojure.lang.LispReader and may be changed or removed at any time.
In my opinion the best/safest way that works when you want it to for any number and fails when it isn't a number is this:
(defn parse-number
"Reads a number from a string. Returns nil if not a number."
[s]
(if (re-find #"^-?\d+\.?\d*$" s)
(read-string s)))
e.g.
(parse-number "43") ;=> 43
(parse-number "72.02") ;=> 72.02
(parse-number "009.0008") ;=> 9.008
(parse-number "-92837482734982347.00789") ;=> -9.2837482734982352E16
(parse-number "89blah") ;=> nil
(parse-number "z29") ;=> nil
(parse-number "(exploit-me)") ;=> nil
Works for ints, floats/doubles, bignums, etc. If you wanted to add support for reading other notations, simply augment the regex.
Brian Carper's suggested approach (using read-string) works nicely, but only until you try and parse zero-padded numbers like "010". Observe:
user=> (read-string "010")
8
user=> (read-string "090")
java.lang.RuntimeException: java.lang.NumberFormatException: Invalid number: 090 (NO_SOURCE_FILE:0)
This is because clojure tries to parse "090" as an octal, and 090 is not a valid octal!
Brian carper's answer is almost correct. Instead of using read-string directly from clojure's core. Use clojure.edn/read-string. It is safe and it will parse anything that you throw at it.
(ns edn-example.core
(require [clojure.edn :as edn]))
(edn/read-string "2.7"); float 2.7
(edn/read-string "2"); int 2
simple, easy and execution safe ;)
Use bigint and bigdec
(bigint "1")
(bigint "010") ; returns 10N as expected
(bigint "111111111111111111111111111111111111111111111111111")
(bigdec "11111.000000000000000000000000000000000000000000001")
Clojure's bigint will use primitives when possible, while avoiding regexps, the problem with octal literals or the limited size of the other numeric types, causing (Integer. "10000000000") to fail.
(This last thing happened to me and it was quite confusing: I wrapped it into a parse-int function, and afterwards just assumed that parse-int meant "parse a natural integer" not "parse a 32bit integer")
These are the two best and correct approaches:
Using Java interop:
(Long/parseLong "333")
(Float/parseFloat "333.33")
(Double/parseDouble "333.3333333333332")
(Integer/parseInt "-333")
(Integer/parseUnsignedInt "333")
(BigInteger. "3333333333333333333333333332")
(BigDecimal. "3.3333333333333333333333333332")
(Short/parseShort "400")
(Byte/parseByte "120")
This lets you precisely control the type you want to parse the number in, when that matters to your use case.
Using the Clojure EDN reader:
(require '[clojure.edn :as edn])
(edn/read-string "333")
Unlike using read-string from clojure.core which isn't safe to use on untrusted input, edn/read-string is safe to run on untrusted input such as user input.
This is often more convenient then the Java interop if you don't need to have specific control of the types. It can parse any number literal that Clojure can parse such as:
;; Ratios
(edn/read-string "22/7")
;; Hexadecimal
(edn/read-string "0xff")
Full list here: https://www.rubberducking.com/2019/05/clojure-for-non-clojure-programmers.html#numbers
I find solussd's answer work great for my code. Based on it, here's an enhancement with support for Scientific notation. Besides, (.trim s) is added so that extra space can be tolerated.
(defn parse-number
"Reads a number from a string. Returns nil if not a number."
[s]
(if (re-find #"^-?\d+\.?\d*([Ee]\+\d+|[Ee]-\d+|[Ee]\d+)?$" (.trim s))
(read-string s)))
e.g.
(parse-number " 4.841192E-002 ") ;=> 0.04841192
(parse-number " 4.841192e2 ") ;=> 484.1192
(parse-number " 4.841192E+003 ") ;=> 4841.192
(parse-number " 4.841192e.2 ") ;=> nil
(parse-number " 4.841192E ") ;=> nil
(def mystring "5")
(Float/parseFloat mystring)