代码拉取完成,页面将自动刷新
(ns packet.utils
(:require [clojure.string :as str]))
;;;以下所称字节均指无符号字节,即介于0到255的数
;;多字节数据字节序标志,默认高字节在前,这是网络传输的字节序
(def ^:dynamic *big-endian* true)
;;------------------------------------------------------------
;;辅助函数
(defn line-error
"在宏中应用,抛出带行号的错误。解析器和构建器不会抛出错误,只会返回错误"
[line msg & more]
(let [info (cond-> {:line line} (not-empty more)
(assoc :info more))]
(throw (ex-info msg info))))
(defn digit?
"判断字符是否是数字"
[c]
(<= 0x30 (int c) 0x39))
(defn getf
"得到序列中指定元素的下一个元素"
[coll e]
(second (drop-while #(not= % e) coll)))
(defn removef
"移除序列中指定元素及其下一个元素"
[coll e]
(let [[s1 s2] (split-with #(not= % e) coll)]
(concat s1 (nnext s2))))
(defn find-first
"在集合coll中寻找第一个满足pred条件的元素"
[pred? coll]
(some #(when (pred? %) %) coll))
(defn find-last
"在集合coll中寻找第一个满足pred条件的元素"
[pred? coll]
(find-first pred? (reverse coll)))
(defn remove-first
[pred? coll]
(let [[c1 c2] (split-with (complement pred?) coll)]
(concat c1 (rest c2))))
(defn remove-last
[pred? coll]
(reverse (remove-first pred? (reverse coll))))
(defn reverse-split-with
[pred? coll]
(let [[xs1 xs2] (split-with pred? (reverse coll))]
[(reverse xs2) (reverse xs1)]))
(defn keyword-map
"将一个映射所有层次的键都关键字化"
[m]
(cond->> m (map? m)
(reduce-kv (fn [m k v]
(let [k (cond-> k (or (symbol? k) (string? k))
keyword)]
(assoc m k (keyword-map v))))
nil)))
(defn in?
"判断某个值是否在序列中"
[x & xs]
(some #(= x %) xs))
(defn contains-in?
"映射中是否存在指定的键序列,如
(contains-in? {:a {:b nil}} [:a :b])返回true
(contains-in? {:a :any} [:a :b])返回false"
[m ks]
(cond (not (map? m)) false
(empty? ks) true
:else (let [[k & ks] ks]
(and (contains? m k)
(or (empty? ks)
(contains-in? (get m k) ks))))))
(defn positions
"xs中满足条件pred的元素的索引序列"
[pred xs]
(keep-indexed #(when (pred %2) %1) xs))
(defn index-of
"xs中第一个满足pred条件的元素的索引"
[pred xs]
(first (positions pred xs)))
(defn last-index-of
"xs中最后一个满足pred条件的元素的索引"
[pred xs]
(index-of pred (reverse xs)))
;;-----------------------------------------------------
(defn valid-bcd?
"判断一字节压缩bcd码的有效性"
[byte]
(and (<= 0 byte 0x99) (<= (mod byte 16) 9)))
(defn bcd->byte
"一字节压缩bcd码转换为整数"
[b]
{:pre [(valid-bcd? b)]
:post [(<= 0 % 99)]}
(let [h (quot b 16) l (rem b 16)]
(-> h (* 10) (+ l) unchecked-byte)))
(defn byte->bcd
"一字节整数转换为压缩bcd码"
[i]
{:pre [(<= 0 i 99)]
:post [(valid-bcd? %)]}
(let [h (quot i 10) l (rem i 10)]
(-> h (* 16) (+ l))))
(defn byte->hex
"一字节整数转换为用两个16进制字符表示的字符串"
[b]
{:pre [<= 0 b 255]}
(->> [(quot b 16) (rem b 16)]
(map #(char (+ % (if (> % 9) 0x57 0x30))))
(apply str)))
(defn hex->byte
"16进制字符串转换为1字节整数"
[s]
{:pre [(<= (count s) 2)]
:post [(<= 0 % 255)]}
(reduce (fn [n c]
(let [i (int c)
i (cond (<= 97 i 102) (- i 87)
(<= 65 i 70) (- i 55)
(<= 48 i 57) (- i 48)
:else (throw (ex-info "无效字符" {:cause c})))]
(-> n (* 16) (+ i))))
0
s))
;;----------------------------------------------------------------
(defn hex-string->bytes
"空格分隔的16进制字符串转换为字节序列"
[s]
(when-not (empty? s)
(->> (str/split (str/trim s) #"\s+")
(mapcat #(let [s (cond->> % (odd? (count %)) (cons \0))]
(partition 2 s)))
(map hex->byte))))
(defn bytes->hex-string
"字节序列转换为16进制字符串"
[bs]
(->> (map byte->hex bs)
(interpose \space)
(apply str)))
(defn bytes->uint
"字节序列转换为无符号整数"
[bs]
(reduce #(-> %1 (* 256) (+ %2))
0
(cond-> bs (not *big-endian*) reverse)))
(defn uint->bytes
"无符号整数转换为字节序列"
[v len]
(when (pos? len)
(if (int? v)
(cond-> (->> v
(iterate #(unsigned-bit-shift-right % 8))
(map #(bit-and % 0xff))
(take len))
*big-endian* reverse)
(throw (ex-info "参数不是非负整数" {:arg v})))))
(defn bytes->int
"字节序列转换为有符号整数"
[bs]
(if (empty? bs)
0
(let [bs (cond-> bs (not *big-endian*) reverse)]
(reduce #(-> %1 (bit-shift-left 8) (bit-or %2))
(long (unchecked-byte (first bs)))
(rest bs)))))
(defn int->bytes
"有符号整数转换为字节序列"
[v len]
(when (pos? len)
(if (int? v)
(cond-> (->> v
(iterate #(bit-shift-right % 8))
(map #(bit-and % 0xff))
(take len))
*big-endian* reverse)
(throw (ex-info "参数不是整数" {:arg v})))))
(defn bcd+->uint
"bcd序列转换为无符号整数"
[bs]
(reduce #(if (valid-bcd? %2)
(-> %1 (* 100) (+ (bcd->byte %2)))
(reduced nil))
0
(cond-> bs (not *big-endian*) reverse)))
(defn uint->bcd+
"无符号整数转换为bcd序列"
[v len]
(when (pos? len)
(if (int? v)
(cond-> (->> v
(iterate #(quot % 100))
(map #(byte->bcd (rem % 100)))
(take len))
*big-endian* reverse)
(repeat len 0xff))))
(defn bcd+->int
"bcd序列转换为有符号整数"
[bs]
(if (empty? bs)
0
(let [bs (cond-> bs (not *big-endian*) reverse)
fb (first bs)
n? (bit-test fb 7)
bs (cons (bit-clear fb 7) (rest bs))
v (reduce #(if (valid-bcd? %2)
(-> %1 (* 100) (+ (bcd->byte %2)))
(reduced nil))
0
bs)]
(cond-> v n? -))))
(defn int->bcd+
"有符号整数转换为bcd序列"
[v len]
(when (pos? len)
(if (int? v)
(let [n? (neg? v)
value (cond-> v n? -)
bs (->> (iterate #(quot % 100) value)
(map #(byte->bcd (rem % 100)))
(take len))
bs (cond->> bs n?
(map-indexed (fn [i b]
(cond-> b (= i (dec len))
(bit-set 7)))))]
(cond-> bs *big-endian* reverse))
(repeat len 0xff))))
(defn leader-partition
"将满足条件的元素及其后面的元素分在同一组,直到遇到另一个满足条件的元素为止"
[pred coll]
(when-not (empty? coll)
(lazy-seq
(let [[x & xs] coll
ss (if (pred x)
(cons x (take-while #(not (pred %)) xs))
(take-while #(not (pred %)) coll))
n (count ss)]
(cons ss (leader-partition pred (drop n coll)))))))
(defn flat-all
"深度提取满足条件的元素,包括coll自己"
[pred coll]
(cond->> (when (coll? coll) (mapcat #(flat-all pred %) coll))
(pred coll) (cons coll)))
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。