# Partitioning strings into substrings of fixed length

I've got a Clojure function here that's meant to parse a string of form:

"DDXXXYYY"

where DD is meant to be discarded, and XXX and YYY are string representations of integers.

(defn split-id [tileid]
(map #(Integer/parseInt %)
(map (partial apply str)
(partition 3 (drop 2 tileid)))))


Or, written with the threading macro:

(defn split-id [tileid]
(map #(Integer/parseInt %)
(map (partial apply str)
(->> tileid (drop 2) (partition 3)))))


Does anyone have any recommendations for a simple way to do this? It feels like clojure.contrib.string should have a partition function that takes a string and an integer.

I think I've come up with a fairly good block of code for the above function, which I had to extend a bit. I'd love comments and suggestions on the final block.

(defn parse-ints
"Converts all strings in the supplied collection to their integer
representation."
[coll]
(map #(Integer/parseInt %) coll))

(def res-map
^{:doc "Map between the second digit in a MODIS TileID
metadata value and the corresponding resolution."}
{:1 "1000"
:2 "500"
:4 "250"})

(defn tileid->res
"Returns a string representation of the resolution referenced by the
supplied MODIS TileID."
[tileid]
(res-map (keyword (subs tileid 1 2))))

(defn tileid->xy
"Extracts integer representations of the MODIS X and Y coordinates
referenced by the supplied MODIS TileID."
[tileid]
(parse-ints
(map (partial apply str)
(partition 3 (subs tileid 2)))))

(defn split-id
"Returns a sequence containing the resolution, X and Y
coordinates (on the MODIS grid) referenced by the supplied MODIS
TileID."
[tileid]
(flatten
((juxt tileid->res
tileid->xy) tileid)))


Alternative solution is to keep it really simple:

(defn extract-int [s start end]
(Integer/parseInt (subs s start end)))

(defn split-id [s]
(list
(extract-int s 2 5)
(extract-int s 5 8)))


I believe that hardcoding two calls to extract-int is a simpler and more elegant way to meet the requirement than a solution which involves a map. Sure it's nice to use abstraction with higher-order functions, but YAGNI principle applies.

You could try the following, using the Java substring method and a vector of offsets:

(defn split-id [tileid]
(map
#(Integer. (.substring tileid % (+ % 3)) )
[2 5]))


Just a though, perhaps you're looking at this the wrong way. This is a parsing question, and simple parses are often best executed through regular expressions. Clojure has reader macros and special functions to work with Java regexes.