Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Clojure let me define zero-padded numbers?

Tags:

clojure

I'm trying to bind the following grid to a symbol

(def grid [08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
           49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
           81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
           52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
           22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
           24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
           32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
           67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
           24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
           21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
           78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
           16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
           86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
           19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
           04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
           88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
           04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
           20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
           20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
           01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48])

This yields Exception in thread "main" java.lang.NumberFormatException: Invalid number: 08 (11.clj:1). Why can't I do this in Clojure? Are there any workarounds?


Clarification

All I want to do is paste this grid somewhere and have it act as if there were no leading zeros, even if it takes a little coercion. I don't want to have to drop all of the zeros in my editor, I'd just like to paste it in there and have each number behave as if there were no leading zeros.


One other strange detail

The REPL seems to allow zero-padded numbers, but executing a .clj file with java -cp clojure.jar -i some_file.clj will throw the error.

like image 921
Blaine Lafreniere Avatar asked Jul 26 '10 16:07

Blaine Lafreniere


4 Answers

Regular expressions will remove leading zeros

(re-seq #"[1-9]+[0-9]*|0{2}" the-string)

The regex phrase breaks down as follows:

[1-9]+ ;; one or more repetitions of 1-9 (i.e. must start with 1-9)
[0-9]* ;; zeros are ok after the first non-zero number has been found
|0{2}  ;; or if the above can't be found, just look for two zeros

A more general expression is

#"[1-9]+[0-9]*|(?<=\s)0+(?=\s)"

which does the same thing but in the 'or' portion it uses positive lookahead and lookbehind assertions to look for a sequence of one or more zeros preceded and followed by whitespace.

With the leading zeros stripped (map read-string (re-seq ....)) works just fine

like image 87
JJ_ Avatar answered Dec 01 '22 10:12

JJ_


SPOILER ALERT:

Since you're solving a Project Euler problem, you might not want to read this, even though it's only about the "how to read in the data?" part of it...


The reason this happens is as explained in the other answers. The correct solution would be to embed the input in your code as a string -- with linebreaks! -- and use something like the following:

(->> the-string
     (.split #"\n")
     (map #(.split #"\s+" %))
     (map (partial drop-while empty?))
     ;; this just doesn't care about the leading 0
     (mapcat (partial map #(Integer/parseInt %)))
     vec)

This should produce a vector of your numbers. For a two-dimentional vector, you could replace the mapcat with a regular map and put in an extra (map vec) before the final vec.

If you prefer to put the input in a separate file and have Clojure read it from there, replace the-string and (.split #"\n") with a call to line-seq on a reader on your file.x

like image 22
Michał Marczyk Avatar answered Dec 01 '22 10:12

Michał Marczyk


Leading zeros imply an octal number, so 08 is not valid. Many programming languages use this convention, starting with C.

like image 36
Ned Batchelder Avatar answered Dec 01 '22 11:12

Ned Batchelder


numbers with a leading 0 are read as if they where in base 8 so any charcter not between 0-7 will not work. to fix this you can append 10r08 to explicity specify the base.

user> 10r08
8
user> 08
; Evaluation aborted.

This messes up your nice formatting though :( sorry about that. you could write a little macro to change this for a block if you want to preserve your nicely formatted code.

like image 30
Arthur Ulfeldt Avatar answered Dec 01 '22 10:12

Arthur Ulfeldt