这个解决方案对我有用。整个 3Byte 被编码成 4 个字符。我调整了字母表来替换一些误导性字符(0、O、i、l、1 等)。base64 填充('=')在编码后被删除,并将在函数内部解码之前添加。CRC4 并不完美 - 总比没有 CRC 好 :)
我很高兴收到任何反馈,建议进一步优化。谢谢。
谷歌表格前端:

本文档中的另一个选项卡,您可以在其中定义变体/系列/食谱:

下面是应用程序脚本的代码(特别感谢 @Kamil Kiełczewski 的 base64 snippert):
// Convert a hex string to a byte array
function hexToBytes(hex) {
// https://stackoverflow.com/a/34356351/14226613
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
function hexToBytes2(hexString) {
//https://stackoverflow.com/a/62365404/14226613
return hexString.match(/.{1,2}/g).map(x=> +('0x'+x));
}
// Convert a byte array to a hex string
function bytesToHex(bytes) {
// https://stackoverflow.com/a/34356351/14226613
for (var hex = [], i = 0; i < bytes.length; i++) {
var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
hex.push((current >>> 4).toString(16));
hex.push((current & 0xF).toString(16));
}
return hex.join("");
}
function hex2bin(hex, fill = false){
//https://stackoverflow.com/a/45054052/14226613
let bin = (parseInt(hex, 16).toString(2)).padStart(8, '0');
if (fill) {
//https://stackoverflow.com/a/27641835/14226613
bin = "000000000000000000000000".substr(bin.length) + bin;
}
return bin
}
function b64(){
const abc = "ABCDEFGH!JKLMN=PQRSTUVWXYZabcdefghijk:mnopqrstuvwxyz+-$%23456789"; // base64 alphabet
function encode (byteArray) {
//https://stackoverflow.com/a/62365404/14226613
const bin = n => n.toString(2).padStart(8,0); // convert num to 8-bit binary string
const l = byteArray.length
let result = '';
for(let i=0; i<=(l-1)/3; i++) {
let c1 = i*3+1>=l; // case when "=" is on end
let c2 = i*3+2>=l; // case when "=" is on end
let chunk = bin(byteArray[3*i]) + bin(c1? 0:byteArray[3*i+1]) + bin(c2? 0:byteArray[3*i+2]);
let r = chunk.match(/.{1,6}/g).map((x,j)=> j==3&&c2 ? '=' :(j==2&&c1 ? '=':abc[+('0b'+x)]));
result += r.join('');
}
//remove padding - http://jsfiddle.net/bicycle/c49fgz8x/
result = result.replace(/={1,2}$/, '');
return result;
}
function decode (str) {
//https://stackoverflow.com/a/62364519/14226613
let result = [];
//add padding http://jsfiddle.net/bicycle/c49fgz8x/
str = str + Array((4 - str.length % 4) % 4 + 1).join('=');
for(let i=0; i<str.length/4; i++) {
let chunk = [...str.slice(4*i,4*i+4)]
let bin = chunk.map(x=> abc.indexOf(x).toString(2).padStart(6,0)).join('');
let bytes = bin.match(/.{1,8}/g).map(x=> +('0b'+x));
result.push(...bytes.slice(0,3 - (str[4*i+2]=="=") - (str[4*i+3]=="=")));
}
return result;
}
return {
encode: encode,
decode: decode
}
}
var crc4 = function(data) {
//https://gist.github.com/bryc/5916452ad0d1ef5c39f1a3f19566d315
var POLY = 0xC, INIT = 0, XOROUT = 0;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ data[i];
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
}
return (crc ^ XOROUT) & 0xF;
};
function get_family(input, sheet, range) {
//get array with family names
let familiesValNames =sheet.getRange(range).getValues();
let obj = {};
for (i=0; i < familiesValNames.length; i++) {
if ( //if input is string - loop through array and find the corresponding number
(typeof input === 'string' && input == familiesValNames[i]) ||
//if it is a number between 1..15
(typeof input === 'number' && input == (i+1))) {
obj.number = i + 1;
//first values are in row 4 (=offset)
let sRange = 'A' + (4 + i) + ':P' + (4 + i)
obj.names = sheet.getRange(sRange).getValues();
break;
}
}
return obj
}
function set_family_object (sheet, range, fixed = false){
let famtypes={1:{family:["Spares ACME 1"],types:[["spare","Alpha v2","Alpha v1","Alpha v0","spare","Beta v2","Beta v1","Beta v0","spare","Gamma v2","Gamma v1","Gamma v0","spare","Delta v2","Delta v1","Delta v0"]]},2:{family:["Spares ACME 2"],types:[["spare","spare","spare","spare","spare","spare","spare","spare","spare","spare","spare","spare","Omega v2","Omega v2","Omega v1","Omega v0"]]},3:{family:["ACME Tools"],types:[["p612 lcp2","p612 lcp1","p612 lcp0","p512 lcp2","p512 lcp1","p512 lcp0","p671 lcp2","p671 lcp1","p671 lcp0","p471 lcp2","p471 lcp1","p471 lcp0","blm v2","blm v1","blm v0","common"]]},4:{family:["Animals"],types:[["Sea Otter","Cat","Panda","Fox","Dog","Lemur","Penguin","Mulgara","Degu","Kiwi","Koala","Monkey","Whale","Oribi","Chimpanzee","Deer"]]},5:{family:["Male Names"],types:[["James","John","Robert","Michael","Willian","David","Richard","Thomas","Charles","Daniel","Matthew","Donald","Mark","Brian","Edward","George"]]},6:{family:["Female Names"],types:[["Olivia","Emma","Ava","Sophia","Isabella","Charlotte","Amelia","Mia","Harper","Evelyn","Emily","Ella","Camila","Luna","Mila","Aria"]]},7:{family:["Car Brands"],types:[["Skoda","Renault","Citroen","Dacia","BMW","Audi","VW","Ford","Peugeot","Honda","Hyundai","Toyota","Kia","Opel","Porsche","Tata"]]},8:{family:["Horror Movies"],types:[["Wrong Turn","Descent","Hostel","Vacancy","Joy ride","Joy Ride","Midsommar","Cave","Eden Lake","Frozen","Ruins","Turistas","Hills have Eyes","Cabin of Woods","Soon the Darkness","Deep"]]},9:{family:["Things for Salad"],types:[["Lettuce","Cucumber","Cheese","Carrot","Tomato","Spinach","Crouton","Bacon","Egg","Onion","Chicken","Avocado","Pepper","Cabbage","Olive Oil","Feta"]]},10:{family:["TV Scientist"],types:[["Spock","Gaius Baltar","Leonard McCoy","Dr Bruce Banner","MacGyver","Dr Krieger","Walter White","Dexter","Lex Luthor","Walter Bishop","Data","The Doctor","Dr Quest","Dana Scully","Jimmy Neutron","Howard Wolowitz"]]},11:{family:["Funny Movies"],types:[["Spaceballs","Airplane!","Monty Python","Blazin Saddles","Lego Movie 2","Shrek","Naked gun","Austin Powers","Shaun of the Dead","Finding Nemo","The Big Lebowski","Dumb and Dumber","Simpsons","Toy Story","South Park","Life of Brian"]]},12:{family:["Actors"],types:[["Jamie Foxx","Val Kilmer","Christian Bale","Cate Blanchett","Jim Carrey","Meryl Streep","Joaquin Phoenix","Sam Rockwell","Leonardi DiCaprio","Heath Ledger","Robin Williams","Bill Murray","Will Ferrel","Jack Nicholson","Kevin spacey","Tom Cruise"]]},13:{family:["Tech Blogs"],types:[["TechCrunch","Wired","TechnoByte","Golem","Heise","Gizmodo","Engadget","Ars Technica","Techaeris","Top10Tech","10xDS","The Verge","TECHi","Urbangeekz","Techsppoks","Mashable"]]},14:{family:["PC Brands"],types:[["Asus","Intel","Dell","HP","Alienware","Microsoft","Apple","ACer","Sony","MSI","Razer","Toshiba","Gateway","LG","Compaq","Panasonic"]]},15:{family:["Evil Companies"],types:[["Facebook","Comcast","Time Warner","Google","Apple","Twitter","Go Daddy","Verizon","Yahoo","Microsoft","Zynga","BuzzFeed","McAfee","Amazon","Youtube","Hulu"]]}};
if (fixed) {
return famtypes
} else {
let familiesValNames =sheet.getRange(range).getValues();
let sRange
let obj = {};
for (i=0; i < 15; i++) {
sRange = 'A' + (4 + i) + ':P' + (4 + i)
Object.assign(obj, {[i +1]: {family: familiesValNames[i]}});
obj[i +1].types = sheet.getRange(sRange).getValues();
}
}
return JSON.stringify(obj);
}
function encoder (sheet, currentRow, colOffset, typeColNo, famSheet, famSheetTypesRange) {
let ret = {}
var str = ''
//loop through columns 3 to 18 of the corresponding row and iterate if its checked -> result binary string
for (i=0; i < 16; i++) {
str = (sheet.getRange(currentRow, (i+colOffset)).isChecked()) ? str + '1' : str + '0';
}
//shift one byte to left for easier calculation
//result are the first 2 byte (0xnnnnFF) of 3 (0xFFFFFF)
let var_bin = ((+parseInt(str,2)) << 8).toString(2)
//format binary as 3 byte
var_bin = ("000000000000000000000000".substr(var_bin.length) + var_bin);
//convert to hex
ret.variant_hex = parseInt(var_bin, 2).toString(16)
//get selected family type
ret.family_str = sheet.getRange(currentRow, typeColNo).getValue()
//get number of this selected type and convert it to hex
ret.family_hex = (get_family(ret.family_str, famSheet, famSheetTypesRange).number >>> 0).toString(16).toUpperCase();
//calculate intermedia hex value; add a trailing '0' to move the family to the upper 4bits of the last byte
ret.joined_hex = (parseInt(ret.variant_hex, 16) + parseInt((ret.family_hex + '0'), 16)).toString(16)
//convert to binary - better to make CRC with binary (1111 1111) than with HEX (ff)
let joined_bin = (parseInt(ret.joined_hex, 16)).toString(2)
//get crc and convert it to hex
ret.crc_hex = crc4(joined_bin).toString(16).toUpperCase()
//final hex code
ret.final_hex = (parseInt(ret.joined_hex, 16) + parseInt(ret.crc_hex, 16)).toString(16).toLocaleUpperCase()
//prepare and encode into base64
/** @type {number[]} */
ret.finalByteArr = [];
ret.finalByteArr[0] = ((parseInt(ret.final_hex, 16) & (parseInt('ff0000', 16))) >>> 16)
ret.finalByteArr[1] = ((parseInt(ret.final_hex, 16) & (parseInt('00ff00', 16))) >>> 8)
ret.finalByteArr[2] = (parseInt(ret.final_hex, 16) & (parseInt('0000ff', 16)))
//ret.finalByteArr = hexToBytes(ret.final_hex)
ret.b64 = b64().encode(ret.finalByteArr)
return ret
}
function decoder(str) {
var ret = {}
//will find on the end of the string the code; trailing whitespaces will be ignored
const regEx = /^(?:.*)#(.{4})(?:\s*)$/
//check if string is valid (checksum will be checked later)
ret.strValid = regEx.test(str);
if (ret.strValid) {
let result = str.match(regEx)
//first capturing group
ret.b64 = result[1];
//convert to a byte array
ret.byteArray = b64().decode(ret.b64)
//convert to hex string
ret.hex = bytesToHex(ret.byteArray).toString(16).toUpperCase();
//convert the hex string to binary
ret.binary = hex2bin(ret.hex, true)
//get crc
ret.crc = (parseInt(ret.binary, 2) & parseInt('00000f', 16)).toString(16).toUpperCase();
//get last 2 bytes (mask the 1st out) and check if its suits to the checksum
let toCheck = (parseInt(ret.binary, 2) & parseInt('fffff0', 16)).toString(2);
ret.crcValid = (crc4(toCheck).toString(16).toUpperCase() == ret.crc) ? true: false;
//get only variant
ret.variant_bin = ((parseInt(ret.binary, 2) & parseInt('ffff00', 16)) >>> 8).toString(2);
//fill with zero's & make a mirror bit set for easier handling later -> [0] = lowest bit
let variant_bin_ext = (("0000000000000000".substr(ret.variant_bin.length)) + ret.variant_bin.toString())
ret.variant_bin_mirr = variant_bin_ext.split("").reverse().join("");
//convert to hex
ret.variant_hex = parseInt(ret.variant_bin, 2).toString(16).toUpperCase()
//get type - mask everythin irrelevant out and move 4 bits to right
ret.type = parseInt(((parseInt(ret.binary, 2) & parseInt('0000f0', 16)) >>> 4), 10)
}
else {
ret.strValid = false;
}
return ret
}
function onEdit(event){
var sheet = event.source.getActiveSheet();
var actualSheetName = sheet.getName();
var lastColumnRow = sheet.getLastColumn();
var editRange = sheet.getActiveRange();
var editCol = editRange.getColumn();
var editRow = editRange.getRow();
var value = sheet.getActiveCell().getValue();
var adress = sheet.getActiveCell().getA1Notation();
var familiesSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Families');
//evaluate if something has been changed in 'Familees'
if (actualSheetName == 'Families') {
let all_types = set_family_object(familiesSheet, 'Q4:Q18', true)
Logger.log(all_types)
Logger.log(all_types[1].family)
Logger.log(all_types[1].types)
Logger.log(all_types[15].family)
Logger.log(all_types[15].types)
}
//evaluate and fill out legend on the top of sheet
if (adress == 'S2' && actualSheetName == 'Spares') {
const str = sheet.getActiveCell().getValue();
var famObj = get_family(str, familiesSheet, 'Q4:Q18')
sheet.getRange('C2:R2').setValues(famObj.names)
}
//getRange(row, column, [numRows], [numColumns]) || getRange(a1Notation)
if (sheet.getActiveCell().getRow() >= 6 && sheet.getActiveCell().getRow() <= 21
&& sheet.getActiveCell().getColumn() >= 3 && sheet.getActiveCell().getColumn() <= 19
&& actualSheetName == 'Spares') {
let currentRow = sheet.getActiveCell().getRow();
let currentCol = sheet.getActiveCell().getColumn();
//calculate code
let codeEnc = encoder(sheet, currentRow, 3, 19, familiesSheet, 'Q4:Q18')
if (sheet.getRange(currentRow, 1).getValue().length > 3) {
sheet.getRange(currentRow, 20).setValue(codeEnc.crc_hex);
sheet.getRange(currentRow, 20).setComment('')
sheet.getRange(currentRow, 21).setValue(codeEnc.b64);
sheet.getRange(currentRow, 21).setComment('')
} else {
sheet.getRange(currentRow, 20).setValue('n/a');
sheet.getRange(currentRow, 20).setComment('Please enter a product name in the 1st column.')
sheet.getRange(currentRow, 21).setValue('n/a');
sheet.getRange(currentRow, 21).setComment('Please enter a product name in the 1st column.')
}
let decoded = decoder('grgrgr #' + codeEnc.b64)
Logger.log(codeEnc)
Logger.log(decoded)
var famObj2 = get_family(decoded.type, familiesSheet, 'Q4:Q18')
Logger.log(famObj2)
}
可以使用以下 HTML/JS 片段尝试/解码结果。它又快又脏。只需输入例如:
- 气动接头#Xs2a
- 相机#!$cg
- 电源 24V #p%qz
您可以尝试手动更改 base64 代码 - 以测试 CRC4 是否有效。
var crc4 = function(data) {
//https://gist.github.com/bryc/5916452ad0d1ef5c39f1a3f19566d315
var POLY = 0xC, INIT = 0, XOROUT = 0;
for(var crc = INIT, i = 0; i < data.length; i++) {
crc = crc ^ data[i];
for(var j = 0; j < 8; j++) {
crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
}
}
return (crc ^ XOROUT) & 0xF;
};
// Convert a hex string to a byte array
function hexToBytes(hex) {
// https://stackoverflow.com/a/34356351/14226613
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
// Convert a byte array to a hex string
function bytesToHex(bytes) {
// https://stackoverflow.com/a/34356351/14226613
for (var hex = [], i = 0; i < bytes.length; i++) {
var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
hex.push((current >>> 4).toString(16));
hex.push((current & 0xF).toString(16));
}
return hex.join("");
}
function hex2bin(hex, fill = false){
//https://stackoverflow.com/a/45054052/14226613
let bin = (parseInt(hex, 16).toString(2)).padStart(8, '0');
if (fill) {
//https://stackoverflow.com/a/27641835/14226613
bin = "000000000000000000000000".substr(bin.length) + bin;
}
return bin
}
function b64(){
const abc = "ABCDEFGH!JKLMN=PQRSTUVWXYZabcdefghijk:mnopqrstuvwxyz+-$%23456789"; // base64 alphabet
function encode (byteArray) {
//https://stackoverflow.com/a/62365404/14226613
const bin = n => n.toString(2).padStart(8,0); // convert num to 8-bit binary string
const l = byteArray.length
let result = '';
for(let i=0; i<=(l-1)/3; i++) {
let c1 = i*3+1>=l; // case when "=" is on end
let c2 = i*3+2>=l; // case when "=" is on end
let chunk = bin(byteArray[3*i]) + bin(c1? 0:byteArray[3*i+1]) + bin(c2? 0:byteArray[3*i+2]);
let r = chunk.match(/.{1,6}/g).map((x,j)=> j==3&&c2 ? '=' :(j==2&&c1 ? '=':abc[+('0b'+x)]));
result += r.join('');
}
//remove padding - http://jsfiddle.net/bicycle/c49fgz8x/
result = result.replace(/={1,2}$/, '');
return result;
}
function decode (str) {
//https://stackoverflow.com/a/62364519/14226613
let result = [];
//add padding http://jsfiddle.net/bicycle/c49fgz8x/
str = str + Array((4 - str.length % 4) % 4 + 1).join('=');
for(let i=0; i<str.length/4; i++) {
let chunk = [...str.slice(4*i,4*i+4)]
let bin = chunk.map(x=> abc.indexOf(x).toString(2).padStart(6,0)).join('');
let bytes = bin.match(/.{1,8}/g).map(x=> +('0b'+x));
result.push(...bytes.slice(0,3 - (str[4*i+2]=="=") - (str[4*i+3]=="=")));
}
return result;
}
return {
encode: encode,
decode: decode
}
}
function set_family_object (sheet, range, fixed = false){
let famtypes={1:{family:["Spares ACME 1"],types:[["spare","Alpha v2","Alpha v1","Alpha v0","spare","Beta v2","Beta v1","Beta v0","spare","Gamma v2","Gamma v1","Gamma v0","spare","Delta v2","Delta v1","Delta v0"]]},2:{family:["Spares ACME 2"],types:[["spare","spare","spare","spare","spare","spare","spare","spare","spare","spare","spare","spare","Omega v2","Omega v2","Omega v1","Omega v0"]]},3:{family:["ACME Tools"],types:[["p612 lcp2","p612 lcp1","p612 lcp0","p512 lcp2","p512 lcp1","p512 lcp0","p671 lcp2","p671 lcp1","p671 lcp0","p471 lcp2","p471 lcp1","p471 lcp0","blm v2","blm v1","blm v0","common"]]},4:{family:["Animals"],types:[["Sea Otter","Cat","Panda","Fox","Dog","Lemur","Penguin","Mulgara","Degu","Kiwi","Koala","Monkey","Whale","Oribi","Chimpanzee","Deer"]]},5:{family:["Male Names"],types:[["James","John","Robert","Michael","Willian","David","Richard","Thomas","Charles","Daniel","Matthew","Donald","Mark","Brian","Edward","George"]]},6:{family:["Female Names"],types:[["Olivia","Emma","Ava","Sophia","Isabella","Charlotte","Amelia","Mia","Harper","Evelyn","Emily","Ella","Camila","Luna","Mila","Aria"]]},7:{family:["Car Brands"],types:[["Skoda","Renault","Citroen","Dacia","BMW","Audi","VW","Ford","Peugeot","Honda","Hyundai","Toyota","Kia","Opel","Porsche","Tata"]]},8:{family:["Horror Movies"],types:[["Wrong Turn","Descent","Hostel","Vacancy","Joy ride","Joy Ride","Midsommar","Cave","Eden Lake","Frozen","Ruins","Turistas","Hills have Eyes","Cabin of Woods","Soon the Darkness","Deep"]]},9:{family:["Things for Salad"],types:[["Lettuce","Cucumber","Cheese","Carrot","Tomato","Spinach","Crouton","Bacon","Egg","Onion","Chicken","Avocado","Pepper","Cabbage","Olive Oil","Feta"]]},10:{family:["TV Scientist"],types:[["Spock","Gaius Baltar","Leonard McCoy","Dr Bruce Banner","MacGyver","Dr Krieger","Walter White","Dexter","Lex Luthor","Walter Bishop","Data","The Doctor","Dr Quest","Dana Scully","Jimmy Neutron","Howard Wolowitz"]]},11:{family:["Funny Movies"],types:[["Spaceballs","Airplane!","Monty Python","Blazin Saddles","Lego Movie 2","Shrek","Naked gun","Austin Powers","Shaun of the Dead","Finding Nemo","The Big Lebowski","Dumb and Dumber","Simpsons","Toy Story","South Park","Life of Brian"]]},12:{family:["Actors"],types:[["Jamie Foxx","Val Kilmer","Christian Bale","Cate Blanchett","Jim Carrey","Meryl Streep","Joaquin Phoenix","Sam Rockwell","Leonardi DiCaprio","Heath Ledger","Robin Williams","Bill Murray","Will Ferrel","Jack Nicholson","Kevin spacey","Tom Cruise"]]},13:{family:["Tech Blogs"],types:[["TechCrunch","Wired","TechnoByte","Golem","Heise","Gizmodo","Engadget","Ars Technica","Techaeris","Top10Tech","10xDS","The Verge","TECHi","Urbangeekz","Techsppoks","Mashable"]]},14:{family:["PC Brands"],types:[["Asus","Intel","Dell","HP","Alienware","Microsoft","Apple","ACer","Sony","MSI","Razer","Toshiba","Gateway","LG","Compaq","Panasonic"]]},15:{family:["Evil Companies"],types:[["Facebook","Comcast","Time Warner","Google","Apple","Twitter","Go Daddy","Verizon","Yahoo","Microsoft","Zynga","BuzzFeed","McAfee","Amazon","Youtube","Hulu"]]}};
if (fixed) {
return famtypes
} else {
let familiesValNames =sheet.getRange(range).getValues();
let sRange
let obj = {};
for (i=0; i < 15; i++) {
sRange = 'A' + (4 + i) + ':P' + (4 + i)
Object.assign(obj, {[i +1]: {family: familiesValNames[i]}});
obj[i +1].types = sheet.getRange(sRange).getValues();
}
}
return JSON.stringify(obj);
}
function decoder(str) {
var ret = {}
//will find on the end of the string the code; trailing whitespaces will be ignored
const regEx = /^(?:.*)#(.{4})(?:\s*)$/
//check if string is valid (checksum will be checked later)
ret.strValid = regEx.test(str);
if (ret.strValid) {
let result = str.match(regEx)
//first capturing group
ret.b64 = result[1];
//convert to a byte array
ret.byteArray = b64().decode(ret.b64)
//convert to hex string
ret.hex = bytesToHex(ret.byteArray).toString(16).toUpperCase();
//convert the hex string to binary
ret.binary = hex2bin(ret.hex, true)
//get crc
ret.crc = (parseInt(ret.binary, 2) & parseInt('00000f', 16)).toString(16).toUpperCase();
//get last 2 bytes (mask the 1st out) and check if its suits to the checksum
let toCheck = (parseInt(ret.binary, 2) & parseInt('fffff0', 16)).toString(2);
ret.crcValid = (crc4(toCheck).toString(16).toUpperCase() == ret.crc) ? true: false;
//get only variant
ret.variant_bin = ((parseInt(ret.binary, 2) & parseInt('ffff00', 16)) >>> 8).toString(2);
//fill with zero's & make a mirror bit set for easier handling later -> [0] = lowest bit
let variant_bin_ext = (("0000000000000000".substr(ret.variant_bin.length)) + ret.variant_bin.toString())
ret.variant_bin_mirr = variant_bin_ext.split("").reverse().join("");
//convert to hex
ret.variant_hex = parseInt(ret.variant_bin, 2).toString(16).toUpperCase()
//get type - mask everythin irrelevant out and move 4 bits to right
ret.type = parseInt(((parseInt(ret.binary, 2) & parseInt('0000f0', 16)) >>> 4), 10)
}
else {
ret.strValid = false;
}
return ret
}
document.getElementById('ssearch').onclick = function() {
let ttable = document.querySelector("body > table")
ttable.style.visibility = "visible";
let sval = document.getElementsByClassName('searchTerm')[0].value;
let dec_val = decoder(sval);
let famValues = set_family_object(null, null, true)
//console.log(dec_val)
//console.log(famValues)
var tbody = document.querySelector('tbody');
tbody.innerHTML = '';
if (!dec_val.strValid) {
tbody.innerHTML += '<tr style="background-color:red;color:white;"><td>' + 'String Validation' + '</td><td>Input String is not valid!</td></tr>'
} else {
if (dec_val.crcValid) {
tbody.innerHTML += '<tr style="background-color:#93C47D; font-size: 75%;"><td>' + 'String & CRC' + '</td><td>String & CRC valid</td></tr>'
tbody.innerHTML += '<tr style="background-color:#3C6478; color:white"><td>' + 'Family' + '</td><td>' + famValues[dec_val.type]['family'] + '</td></tr>'
for (var i = 0; i < 16; i++) {
tbody.innerHTML += '<tr><td>' +
[
((dec_val.variant_bin_mirr[i] == 1) ?
famValues[dec_val.type]['types'][0][15-i] :
'<s>' + famValues[dec_val.type]['types'][0][15-i] + '</s>'),
((dec_val.variant_bin_mirr[i] == 1) ?
'<span style="background-color:#93C47D; color:white">Compatible</span>' :
'<span style="background-color:red; color:white">NOT Compatible</span>')
].join('</td><td>') + '</td></tr>'
}
} else{
tbody.innerHTML += '<tr style="background-color:red;color: white;"><td>' + 'CRC' + '</td><td>Product Name is wrong - CRC invalid</td></tr>'
}
}
}
th, td {
border: 1px solid black;
}
table {
margin: auto;
width: 40%;
visibility: hidden;
}
@import url(https://fonts.googleapis.com/css?family=Open+Sans);
body{
background: #f2f2f2;
font-family: 'Open Sans', sans-serif;
}
.search {
width: 100%;
position: relative;
display: flex;
}
.searchTerm {
width: 100%;
border: 3px solid #00B4CC;
border-right: none;
padding: 5px;
height: 20px;
border-radius: 5px 0 0 5px;
outline: none;
color: #9DBFAF;
}
.searchTerm:focus{
color: #00B4CC;
}
.searchButton {
width: 100px;
height: 36px;
border: 1px solid #00B4CC;
background: #00B4CC;
text-align: center;
color: #fff;
border-radius: 0 5px 5px 0;
cursor: pointer;
font-size: 20px;
}
/*Resize the wrap to see the search bar change!*/
.wrap{
width: 50%;
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%, -50%);
}
<!-- https://codepen.io/huange/pen/rbqsD -->
<!-- https://uicookies.com/html-search-box/ -->
<div class="wrap">
<div class="search">
<input type="text" class="searchTerm" placeholder="Give me your product name...">
<button type="submit" class="searchButton" id="ssearch">
Check
</button>
</div>
</div>
<br><br><br><br><br><br><br><br>
<table>
<thead>
<th style="width:40%;text-align:left;">Name</th>
<th style="text-align:left;">Value</th>
</thead>
<tbody>
</tbody>
</table>