Search code examples
clojureunpack

Clojure equivalent to the Perl "unpack" function


In Perl, unpack can be used to neatly split a string of fixed-length fields into its parts. What follows is an example of it being used to accomplish this:

# get a 5-byte string, skip 3, then grab 2 8-byte strings, then the rest
my ($leading, $s1, $s2, $trailing) = unpack("A5 x3 A8 A8 A*", $data);

Is there an equivalent to unpack in Clojure?


Solution

  • No, and there's no the corresponding pack.

    I'd use RegExes. Although I can't really tell how exact of an alternative that is since I don't know Perl and how it handles multibyte characters in strings.

    ;; If you prefer named groups.
    (let [data "xxxxx___yyyyyyyyzzzzzzzz1234awerasdf"
          pattern #"(?<leading>.{5}).{3}(?<s1>.{8})(?<s2>.{8})(?<trailing>.*)"
          matcher (re-matcher pattern data)]
      (re-find matcher)
      (into {}
            (map (fn [[n idx]]
                   [(keyword n) (.group matcher ^long idx)]))
            (.namedGroups matcher)))
    
    ;; If you prefer to rely on positions.
    (let [data "xxxxx___yyyyyyyyzzzzzzzz1234awerasdf"
          pattern #"(.{5}).{3}(.{8})(.{8})(.*)"
          [_ leading s1 s2 trailing] (re-matches pattern data)]
      {:leading  leading
       :s1       s1
       :s2       s2
       :trailing trailing})