如何在Google表格中仅用一个公式计算MD5哈希值?
是否可以仅使用原生Google表格公式实现真正完整的MD5哈希?尤其是因为没有像这样的原生函数:
=MD5("text")
=ARRAYFORMULA(MD5(A2:A5))
我在寻找一个纯GS公式解决方案,能够对字符串数组进行MD5校验,可靠、快速且高效地运行。对于长度高达50,000个字符的字符串也欢迎支持。请注意:
- 不 使用 Apps Script / 宏
- 无 插件 / 扩展 / 库
输入/输出示例:
| 文本 | MD5值 |
|---|---|
| Nyuu | a05b9e2769d3e36f9ed2df205a1aa241 |
| 测试字符串 | 6f8db599de986fab7a21625b7916589c |
| 测试2 | 38b0d2ff1c03df82aea67222983d337e |
我没有找到可借鉴的现成工作,因此我从头开始实现了这个fx,因为在电子表格中将这些操作镜像出来相对容易:
=INDEX(LET(BITNOT32, LAMBDA(x, 4294967295-x),
ADDD32, LAMBDA(x, y, MOD(x+y, 4294967296)),
ROTL32, LAMBDA(x, s, MOD(x*2^s, 4294967296)+INT(x/2^(32-s))),
MD5_F, LAMBDA(b, c, d, BITOR(BITAND(b, c), BITAND(BITNOT32(b), d))),
MD5_G, LAMBDA(b, c, d, BITOR(BITAND(b, d), BITAND(c, BITNOT32(d)))),
MD5_H, LAMBDA(b, c, d, BITXOR(BITXOR(b, c), d)),
MD5_I, LAMBDA(b, c, d, BITXOR(c, BITOR(b, BITNOT32(d)))),
T, LAMBDA(i, MOD(FLOOR(ABS(SIN(i))*4294967296), 4294967296)),
S, LAMBDA(i, INDEX({7, 12, 17, 22; 5, 9, 14, 20; 4, 11, 16, 23; 6, 10, 15, 21}, INT((i-1)/16)+1, MOD(i-1, 4)+1)),
BYTES, LAMBDA(str, MAKEARRAY(LEN(str), 1, LAMBDA(i, j, CODE(MID(str, i, 1))))),
PAD, LAMBDA(str, LET(n, LEN(str), VSTACK(BYTES(str), 128, SEQUENCE(MOD(55-n, 64))*0, MOD(INT(n*8/256^(SEQUENCE(8)-1)), 256)))),
WORDS, LAMBDA(p, MMULT(WRAPROWS(p, 4), {1; 256; 65536; 16777216})),
_ROUND, LAMBDA(st, w, LET(r, REDUCE(st, SEQUENCE(64), LAMBDA(acc, i,
LET(a, INDEX(acc, 1),
b, INDEX(acc, 2),
c, INDEX(acc, 3),
d, INDEX(acc, 4),
rnd, INT((i-1)/16),
g, MOD(INDEX({1; 5; 3; 7}, rnd+1)*(i-1)+INDEX({0; 1; 5; 0}, rnd+1), 16)+1,
f, IFS(rnd=0, MD5_F(b, c, d), rnd=1, MD5_G(b, c, d), rnd=2, MD5_H(b, c, d), TRUE, MD5_I(b, c, d)),
t, ADDD32(ADDD32(ADDD32(a, f), T(i)), INDEX(w, g)), {d; ADDD32(b, ROTL32(t, S(i))); b; c}))), MAKEARRAY(4, 1, LAMBDA(i, j, ADDD32(INDEX(r, i), INDEX(st, i)))))),
padded, PAD(A2),
res, REDUCE({1732584193; 4023233417; 2562383102; 271733878}, SEQUENCE(ROWS(padded)/64), LAMBDA(st, blk, _ROUND(st, WORDS(CHOOSEROWS(padded, SEQUENCE(64, 1, (blk-1)*64+1)))))),
LOWER(TEXTJOIN(, 1, MAP(SEQUENCE(4), LAMBDA(i, LET(n, INDEX(res, i),
TEXTJOIN(, 1, MAP(SEQUENCE(4), LAMBDA(j, TEXT(DEC2HEX(MOD(INT(n/256^(j-1)), 256), 2), "00")))))))))))
该公式的问题包括:
- 太长(1519个字符)
- 性能较差
- 运行十分缓慢
- 最大字符串长度仅为9462个字符
#NUM!在9463个字符处出现错误函数SEQUENCE的参数1 的值为0。它应大于或等于1。
#ERROR!在9464个字符处出现错误在尝试计算此公式时达到了计算限制。
我不确定为什么会失败,或实现MD5校验和时存在哪些限制(例如整数精度、缺失的运算、栈溢出、计算上限等)。
解决方案
在尝试计算此公式时达到了计算限制。
这直接由 LAMBDA MINIONS 导致,表现为在LAMBDA内使用不必要的全局变量和/或使用重量级函数或/和运算,从而消耗有限的开销。在这种情形下进行优化以发挥最大潜力非常有必要。下面给出两种可能的解决方案:
你可以选择将其外包:
- 相当快
- 133个字符长
- 轻量级
- 最大字符串长度为1500个字符
=BYROW(A2:A, LAMBDA(x, HA(x="",,REGEXEXTRACT(INDEX(IMPORTDATA(
"https://api.hashify.net/hash/md5/hex?value="&URLKODLA(x), ":"),,2), "(.*),")
或者你可以(重新)构建它:
- 相对较快
- 1046个字符长
- 支持动态数组
- 在本地运行(完全内部实现)
- 最大字符串长度为 24823 个字符
=BYROW(A2:İNDİS(A:A; XMATCH(;-(A:A="");;-1)); LAMBDA(Ξ; HA(Ξ="";;İNDİS(LET(Џ; 2^32; А; LIN($1:$64);
Б; ENT(ASS(SEN(А))*Џ); В; TETO(А/16); Г; {1;256;2^16;2^24}; Д; LIN($1:$16)-1; Е;
{Д+1;MOD(Д*5+1;16)+1;MOD(Д*3+5;16)+1;MOD(Д*7;16)+1}; Ж; TOCOL(REDUCE(TOROW(;1); LIN($1:$4);
LAMBDA(Л; И; HSTACK(Л; MTRANS(HSTACK({7;12;17;22};{5;9;14;20};{4;11;16;23};{6;10;15;21})))))); З; 2^Ж;
И; LAMBDA(Й; К; MOD(REDUCE(Й; А; LAMBDA(Л; М; LET(Н; İNDİS(Л; 2); О; İNDİS(Л; 3); П; İNDİS(Л; 4);
Р; İNDİS(В; М); С; MOD(İNDİS(Л; 1)+VELG(Р; BITXOR(П; BİTVE(Н; BITXOR(О; П))); BITXOR(О;
BİTVE(П; BITXOR(Н; О))); BITXOR(BITXOR(Н; О); П); BITXOR(О; BITOR(Н; Џ-1-П)))+İNDİS(Б; М)+
İNDİS(К; İNDİS(Е; М)); Џ); Т; С*İNDİS(З; М); {П;MOD(Н+BITOR(MOD(Т;Џ); ENT(Т/Џ)); Џ);Н;О})))+Й;
Џ)); У; DŁ(Ξ); Ф; MOD(55-У; 64); Х; DÇARP(WRAPROWS(TOCOL(VSTACK(KOD(MID(Ξ; SEQUENCE(У); 1)); 128;
HA(Ф=0;;SEQUENCE(Ф;1;;)); MOD(ENT(У*8/256^(LIN($1:$8)-1)); 256)); 1); 4); Г); Ц; REDUCE(
{1732584193;4023233417;2562383102;271733878}; SEQUENCE(LINS(Х)/16); LAMBDA(Ч; Ш; И(Ч; CHOOSEROWS(Х;
SEQUENCE(16; 1; Ш*16-15))))); SMÅ(JOIN(; MAP(Д+1; LAMBDA(Щ; DECHEX(MOD(ENT(İNDİS(Ц; TETO(Щ/4))
/İNDİS(Г; MOD(Щ-1; 4)+1)); 256); 2)
额外内容:
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

