【发布时间】:2011-12-21 02:51:39
【问题描述】:
如何计算特定单元格中文本的 MD5 或 SHA1 哈希值并将其设置为 Google 电子表格中的另一个单元格?
有=ComputeMD5(A1)或=ComputeSHA1(A1)这样的公式吗?
或者是否可以为此编写自定义公式?怎么样?
【问题讨论】:
标签: google-sheets google-search-api
如何计算特定单元格中文本的 MD5 或 SHA1 哈希值并将其设置为 Google 电子表格中的另一个单元格?
有=ComputeMD5(A1)或=ComputeSHA1(A1)这样的公式吗?
或者是否可以为此编写自定义公式?怎么样?
【问题讨论】:
标签: google-sheets google-search-api
打开Tools > Script Editor然后粘贴以下代码:
function MD5 (input) {
var rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, input);
var txtHash = '';
for (i = 0; i < rawHash.length; i++) {
var hashVal = rawHash[i];
if (hashVal < 0) {
hashVal += 256;
}
if (hashVal.toString(16).length == 1) {
txtHash += '0';
}
txtHash += hashVal.toString(16);
}
return txtHash;
}
之后保存脚本,然后在引用单元格时在电子表格中使用 MD5() 函数。
此脚本基于Utilities.computeDigest() 函数。
【讨论】:
Utilities.sleep(100),以防止它在使用自动填充函数时崩溃(否则您将遇到函数调用频率的限制)
md5sum(1) 所做的相匹配;例如,cli 中的frew 给出了没有换行符的c241183cbf6766bd86061a60d6c8fe1b,但来自函数的cfb5d06a43aad502d0f6219143ba0e34。
hashVal += 256 似乎应该是 hashVal += 128。 Utlities.computeDigest() 返回一个字节数组。字节表示为从 -128 到 127 的整数。添加 128 会将它们转换为 0 到 256 之间的数字。
Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, input, Utilities.Charset.UTF_8);
感谢 gabhubert 提供代码。
这是该代码的 SHA1 版本(非常简单的更改)
function GetSHA1(input) {
var rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_1, input);
var txtHash = '';
for (j = 0; j <rawHash.length; j++) {
var hashVal = rawHash[j];
if (hashVal < 0)
hashVal += 256;
if (hashVal.toString(16).length == 1)
txtHash += "0";
txtHash += hashVal.toString(16);
}
return txtHash;
}
【讨论】:
好的,明白了,
需要创建自定义函数,如中所述 http://code.google.com/googleapps/appsscript/articles/custom_function.html
然后按照中的说明使用 API http://code.google.com/googleapps/appsscript/service_utilities.html
我需要手动输入完整的函数名称,以便在单元格中看到结果。
以下是给出文本的 base 64 编码哈希的代码示例
function getBase64EncodedMD5(text)
{
return Utilities.base64Encode( Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, text));
}
【讨论】:
此方案与其他方案的区别在于:
它解决了上述解决方案中的一些问题,即偏移Utilities.computeDigest 的输出(偏移了 128 而不是 256)
它修复了一个问题,该问题导致一些其他解决方案通过在将其传递给 Utilities.computeDigest() 之前在 input 上调用 JSON.stringify() 为不同的输入生成相同的散列
function MD5(input) {
var result = "";
var byteArray = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, JSON.stringify(input));
for (i=0; i < byteArray.length; i++) {
result += (byteArray[i] + 128).toString(16) + "-";
}
result = result.substring(result, result.length - 1); // remove trailing dash
return result;
}
【讨论】:
要获取一系列单元格的哈希值,请将其添加到 gabhubert 的函数旁边:
function RangeGetMD5Hash(input) {
if (input.map) { // Test whether input is an array.
return input.map(GetMD5Hash); // Recurse over array if so.
} else {
return GetMD5Hash(input)
}
}
并以这种方式在单元格中使用它:
=RangeGetMD5Hash(A5:X25)
它返回与源一相同维度的范围,值将使用公式从单元格向下和向右展开。
它是通用的单值函数到范围函数的转换方法(ref),并且比每个单元格的单独公式要快得多;在这种形式下,它也适用于单个单元格,因此可能值得以这种方式重写源函数。
【讨论】:
如果您想从整行中获取结果,可以使用@gabhubert 回答。来自脚本编辑器。
function GetMD5Hash(value) {
var rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, value);
var txtHash = '';
for (j = 0; j <rawHash.length; j++) {
var hashVal = rawHash[j];
if (hashVal < 0)
hashVal += 256;
if (hashVal.toString(16).length == 1)
txtHash += "0";
txtHash += hashVal.toString(16);
}
return txtHash;
}
function straightToText() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var r = 1;
var n_rows = 9999;
var n_cols = 1;
var column = 1;
var sheet = ss[0].getRange(r, column, n_rows, ncols).getValues(); // get first sheet, a1:a9999
var results = [];
for (var i = 0; i < sheet.length; i++) {
var hashmd5= GetMD5Hash(sheet[i][0]);
results.push(hashmd5);
}
var dest_col = 3;
for (var j = 0; j < results.length; j++) {
var row = j+1;
ss[0].getRange(row, dest_col).setValue(results[j]); // write output to c1:c9999 as text
}
}
然后,从“运行”菜单中,只需运行函数 straightToText() 即可获得结果,并避免对函数错误的过多调用。
【讨论】:
我正在寻找一个可以提供更短结果的选项。你怎么看待这件事?它只返回 4 个字符。不幸的是,它使用了 i's 和 o's,这可能会分别与 L's 和 0's 混淆;使用正确的字体和大写字母并不重要。
function getShortMD5Hash(input) {
var rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, input);
var txtHash = '';
for (j = 0; j < 16; j += 8) {
hashVal = (rawHash[j] + rawHash[j+1] + rawHash[j+2] + rawHash[j+3]) ^ (rawHash[j+4] + rawHash[j+5] + rawHash[j+6] + rawHash[j+7])
if (hashVal < 0)
hashVal += 1024;
if (hashVal.toString(36).length == 1)
txtHash += "0";
txtHash += hashVal.toString(36);
}
return txtHash.toUpperCase();
}
【讨论】:
基于@gabhubert,但使用数组操作获取十六进制表示
function sha(str){
return Utilities
.computeDigest(Utilities.DigestAlgorithm.SHA_1, str) // string to digested array of integers
.map(function(val) {return val<0? val+256 : val}) // correct the offset
.map(function(val) {return ("00" + val.toString(16)).slice(-2)}) // add padding and enconde
.join(''); // join in a single string
}
【讨论】:
我需要在一系列单元格中获取哈希,所以我这样运行它:
function RangeSHA256(input)
{
return Array.isArray(input) ?
input.map(row => row.map(cell => SHA256(cell))) :
SHA256(input);
}
【讨论】: