emacs 中的base64url(更具体来说,slugid)

目标:在emacs中进行base64url的编解码

现状:

  • 原字符串:d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7
  • base64url编码结果:2TpPrk-dRMKapjTv6fxm9w

使用python的base64结果没问题:

但是elisp的结果不对:

怎样让elisp的编码、解码与python中一致?是跟bytes的大端字节序有关么?

看起来是python里面的uuidstringUUID包了一层的缘故,如果直接uuidstring.encode()就和elisp一致了

使用的 Python的 base64算法和 elisp 的不一致。

>>> import base64
>>> s = "d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7"
>>> bs = s.encode()
>>> s2 = base64.b64encode(bs)
b'ZDkzYTRmYWUtNGY5ZC00NGMyLTlhYTYtMzRlZmU5ZmM2NmY3'
>>> s2.decode()
'ZDkzYTRmYWUtNGY5ZC00NGMyLTlhYTYtMzRlZmU5ZmM2NmY3'

都byte了哪还有什么字节序问题。你的python代码和elisp代码逻辑就不一致,可以看看上面两位的回复。

确实,看起来不是base64算法的问题,而是uuid有不同的二进制编码方式。所以base64-encode-string接受字符串、按照常规方式编码为二进制就会有问题。看来需要研究一下uuid,把它转成正确的bytes,然后传给base64-encode-region,

二进制也有字节序问题吧,参见通用唯一识别码 - 维基百科,自由的百科全书

我感觉这里的特殊之处在于,原字符串是uuid,不能直接用标准方法。

目前发现从base64url解码回来,需要补上==后缀并设置BASE64URL。不过这样得到的结果似乎是bytes。

现在的问题是,怎么在elisp中将其转化为十六进制,即下图红色箭头部分:

你的python代码的逻辑是: d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7 → uuid → base64encode

elisp代码的逻辑是: d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7 → base64encode

我没看错吧?你的代码逻辑不一样啊 :joy: 二楼的回复也是这意思啊。

:+1: 我上面字节序可能说得太绝对了,不过我目前打不开维基,能打开了我学习下。

python的base64encode接受的是bytes,emacs的base64-encode接受的是string,所以我原来以为uuid.bytes做的是把string转bytes,相当于emacs的base64-encode中的部分功能,看了二楼的回复才意识到uuid转bytes不是常规按照字符串转bytes,而是去掉-后,当作16进制转bytes😂

elisp貌似没有现成函数处理uuid与slugid之间的转化,我决定这部分就先放在外面处理了。

或者你看python的uuid库,也提供了大端序、小端序

我对你的原始需求还有点不清楚,不确定你是要用elisp代码复刻你截图里python代码的行为还是说只是达成base64encode字符串就可以。我上面的回复只是针对你两端代码逻辑的差异。你如果还需要讨论,可以再明确一下。

另外说一个我的疑惑点,d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7看着已经是一个uuid字符串了,如果只是string转bytes,python肯定有其它方法,用uuid不合适。

原始需求就是能实现以下二者的互转。

原字符串:d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7
base64url编码结果:2TpPrk-dRMKapjTv6fxm9w

至于为什么非要这么转,因为这也算某种标准吧,youtube等网站就是这么实现的。更多参见 GitHub - tanbro/b64uuid: A small Python library and command-line tool to encode/decode UUID to/from a 22 characters shorter URL safe base64 string. 。 我在用的一个软件的deep link也是用的这种方式,给到的链接是2TpPrk-dRMKapjTv6fxm9w,其对应的文件路径为d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7。

直接string转bytes那就是3楼的方案了,不是我希望的。现在明白问题出在哪一步了,elisp似乎没有现成的函数,就先不在emacs中实现了。

查了下Base64 和 Base64URL,没看到和 uuid 有任何关系呀。

在这个测试网站 使用Base64URL 编码试了下,返回的值和你使用 Python 给出的编码结果也不相同。

(base64url-encode-string
 (apply #'string
	(mapcar (lambda (x) (string-to-number x 16))
		(seq-partition (remove ?- "d93a4fae-4f9d-44c2-9aa6-34efe9fc66f7") 2))))
;; => "2TpPrk-dRMKapjTv6fxm9w=="

这就是把byte直接写成string了,转回去就好,==不要就自己去掉。

2 个赞