I have a Google sheet document with a column containing binary data. The binary data is 4 32-bit numbers. This is an example ASCII hex representation of that binary data from one cell: c0a80123000006150000000180004203.
Is there a way in Google sheets to convert this binary number to hex string. I'm looking for something like: BIN2HEX(data[0]) = "0xc0". Regular BIN2HEX doesn't work because the data is larger than it can handle.
Raw text sample file. Converted google sheet.
Update:
Based on one suggestion I've created a Google API script to process the binary data. However, the results come strange to say the least.
function extractip(binary_data) {
var blob = Utilities.newBlob(binary_data);
var ip1 = blob.getBytes()[0];
var ip2 = blob.getBytes()[1];
var ip3 = blob.getBytes()[2];
var ip4 = blob.getBytes()[3];
return Utilities.formatString("%u.%u.%u.%u", ip1, ip2, ip3, ip4);
}
The first 4 bytes in the binary blob represent an IP address, in the form of 192.168.0.X in the attached example. However, the output comes back something like -17.-65.-67.-17.
How about this modification?
At Google Apps Script, the data which was converted by Utilities.newBlob(data).getBytes() is the bytes array of the signed hexadecimal. It is required to convert the bytes array to the unsigned hexadecimal.
Modified script:
function extractip(binary_data) {
var byteAr = Utilities.newBlob(binary_data).getBytes();
return byteAr.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
}
Note:
When you use this, for example, please put =extractip(G2) to "H2" like your shared spreadsheet.
Edit:
If you want to directly retrieve the decimal number like 192.168.0.X, please modify like below. This is a sample modification. So please modify it to your situation.
From:
return byteAr.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
To:
return byteAr.map(function(e) {return e < 0 ? e + 256 : e}).join(",");
Related
I receive a PDF report weekly that I would like to automate into a Google Sheet Workbook using App Script.
I was able to successfully pull the PDF from my Gmail account and extract the text I need but I am having trouble taking the "Table" from the PDF and writing it to Google Sheets.
I used a split function to extract only what I need, and create an "extract" variable that I would like to slice up and use to reconstruct in google sheets. The table extract comes out like this:
Groups
Team A 1,058 1,058
Team B 757 757
Team C 179 6,830 7,009
Team D 1,359 1,359
Total 179 10,004 10,183
Ideally I would like the table to look like this in google sheets:
Teams X Y Total
Team A 1,058 1,058
Team B 757 757 1,514
Team C 179 6,830 7,009
Team D 1,359 1,359
Total 179 10,004 10,183
Primary Question: How can I construct my text extract into an Array that I can push / write to google sheets?
Below is the script I have so far, but I can't seem to write the data to google sheet using the sheet.getrange.setvalues(data). I was expecting to at least be able to push the text to google sheets so maybe I could manipulate it there with formulas.
I receive an error "TypeError: sheet.getrange is not a function". Referring to my primary question above, do I need to reformat the data in a way that can write out correctly to google sheets?
``
function importPDFFromGmail() {
var threads = GmailApp.search("TEST PDF PULL"); // enter search criteria here
var messages = threads[0].getMessages();
var message = messages[messages.length - 1]; // Takes the last thread in the email chain
var attachment = message.getAttachments()[0];
// Is the attachment a PDF file
attachment.setContentTypeFromExtension();
if (attachment.getContentType() === "application/pdf") {
var sheet = SpreadsheetApp.openById('<Sheet ID>').getSheetByName('PDF TEST');
var blob = attachment.getAs(MimeType.PDF);
var filetext = pdfToText( blob, {keepTextfile: false} );
var extract = filetext.split('Sum')[1].split('Sum')[0]; // part between 'Sum' and 'Sum'
var lines = extract.split("\n");
// var extract_delimited = lines.map(function(lin){return lin.split(" ")});
var data = lines.map(function(lin){return lin.split(" ")});
sheet.clear();
sheet.getrange(1,1,data.length,data[0].length).setValues(data);
}
// console.log("extract");
// console.log(extract)
// console.log("lines");
// console.log(lines)
// console.log("extract delimited");
// console.log(extract_delimited;
};
``
First fix the typo in sheet.getRange().
Your String.split() call will get rows that vary in length, while Range.setValues() expects a 2D array where every row is of the same length. You can set the length of all rows to the common max value like this:
const numColumns = Math.max(...data.map(row => row.length));
data.forEach(row => row.length = numColumns);
sheet.getRange('A1')
.offset(0, 0, data.length, numColumns)
.setValues(data);
I did set up routines with the following code to parse CSVs into specific spreadsheets:
function updateGmvAndNmv() {
const threads = GmailApp.search("from:(sender#xxx.de) subject:(uniqueHeader)");
const messages = threads[0].getMessages();
const length = messages.length;
const lastMessage = messages[length - 1];
const attachemnt = lastMessage.getAttachments()[0];
const csvData = Utilities.parseCsv(attachemnt.getDataAsString(), ",");
const ss = SpreadsheetApp.openById("spreadsheetID").getSheetByName("sheetName")
const ssOriginalRange = ss.getRange("A:E");
const ssToPaste = ss.getRange(1,1,csvData.length,csvData[0].length);
ssOriginalRange.clear();
ssToPaste.setValues(csvData)
}
With the latest CSV that I want to parse, I encounter an issue, where I am stuck. I tried to play around with the settings in the app that sends me the report but I can not change the way the CSV is being constructed. When I look at the CSV with a text Editor, I see something like this:
GMV and NMV per partner
"Merchant",,"NMV","GMV bef Cancellation","GMV bef Return"
When I let the above code run, it gets the file and outputs the following in my spreadsheet:
Spreadsheet Example
Which brings up the following questions:
Why do I have "" (double quotes) in row 5? I assumed the parseCsv-function removes those.
With my other CSVs I did not have any issues, but there I did not have any double quotes. Can someone explain the difference in CSVs, once with double quotes and once without?
How can I treat this data correctly, in order to get the data without the "" into the spreadsheet?
Why do I see some ? symbols (please look at the fx input field, row 1 and 7) and how do I get rid of them? The export should be without any format (CSV) and in a text editor I do see all values normally - without any ?.
The issue was the encoding. The correct encoding of the file is UTF-16, while the standard encoding of .getDataAsString() is UTF-8.
I need to get the number of pages of a google document and have come across the following code
function getNumPages() {
var blob = DocumentApp.getActiveDocument().getAs("application/pdf");
var data = blob.getDataAsString();
var pages = parseInt(data.match(/ \/N (\d+) /)[1], 10);
Logger.log("pages = " + pages);
return pages;
}
when run however I get the following error on the 4th line
TypeError: Cannot read property '1' of null
when I log the data variable it outputs
%PDF-1.4
%����
1 0 obj
<</Title (Reddit_Fin)
/Producer (Skia/PDF m92 Google Docs Renderer)>>
endobj
3 0 obj
<</ca 1
/BM /Normal>>
endobj
5 0 obj
<</Filter /FlateDecode
/Length 548>> stream
x��UQk�0~ϯ��%[�
cp�}��lka�����s��H��]Y H�>�>����! ����ϐ-8�~�>��j�B�����>z��w�>p�9�yx���<�&J�d�Q2��K~
���fm|{���4�>���/1��
this is of a 8 page document.
For example, in your situation, how about counting the number of Contents? I thought that when Google Document is converted to the PDF data by retrieving as the blob using Google Apps Script, this method can be used. When this is reflected to your script, it becomes as follows.
Modified script:
From:
var pages = parseInt(data.match(/ \/N (\d+) /)[1], 10);
To:
var pages = data.match(/\/Contents/g).length;
and
var pages = [...data.matchAll(/\/Contents/g)].length;
Note:
If above modification cannot be used, I thought that the external API like https://www.convertapi.com/ might be useful for directly achieving your goal.
References:
match()
matchAll()
I am receiving a CSV file, and in that file I need to Hex Encode one column, and MD5 Hash another column.
Final Outcome I am looking for is to take an incoming CSV file from an FTP account, somehow take data from two columns and encode (as above) the data into two other columns automatically.
While I can do this using a script I found in Excel manually, I really need to automate this process some other way so i am looking for help in knowing how to do this, perhaps sending the CSV file from FTP to Google Sheets and having a script there that automatically adds the two calculations as data is imported - so I can then pull from Google Sheets as the source to the program that will use it (automated)?
Or if there is a program out there that can do this?
Any help is much appreciated!
You can do it inside google sheets
Hex encode
If you want to hex encode decimal digit, you can use this built-in function: DEC2HEX(). Documentation about that function https://support.google.com/docs/answer/3093137?hl=en
MD5 hash
Open Tools > Script Editor then paste the following code:
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;
}
Save the script after that and then use the MD5() function in your spreadsheet while referencing a cell.
In case you need a unique identifier for a Google sheets cell I just got this:
Formula:
=IMPORTXML(https://md5.gromweb.com/?string=&C2, "//*[#id='content']/p[1]/em[2]")
Reference:
https://support.google.com/docs/answer/3093342?hl=en&ref_topic=9199554
Detail:
The idea is to have a column with a standard length string that is unique, the MD5 function is not in Google sheets unless you create a formula.
What did I do:
With the IMPORTXML function, I created a formula and used the URL of the site https://md5.gromweb.com, and took the XPath path of the query result which is the second parameter of the formula, for the query parameter I concatenated several cells in one and from that concatenated cell extract an MD5 from the string resulting from the concatenation, in this way I manage to have an md5 hash that varies each time the cell is updated.
I ran into a need for MD5 hashes myself and since there still isn't a built-in MD5 function provided by Google, I implemented a custom function.
To use it in your Google Sheets spreadsheet, go to Extensions > Apps Script in the menu and in the Apps Script editor that opens add a new file with this content:
/**
* Compute MD5 digest
*
* #param {string} input Input for the MD5 digest algorithm
* #customfunction
*/
const MD5 = (input) => Utilities
.computeDigest(Utilities.DigestAlgorithm.MD5, input)
.map((hashByte) => ((hashByte + 256) % 256).toString(16).padStart(2, '0'))
.join('')
.toUpperCase();
You can then use =MD5 in the sheet cell(s).
For example =MD5("My own string") will result in 1C978176903D20CD5EA1B40FD9FE909D MD5 hash.
In a Google spreadsheet I pull some numbers from Google Analytics via Apps script and the Analytics API.
One of the numbers is the bounce rate, which is returned in the format 42.380071394743425. I want to display this with two digits after the decimal point (and I need to add a percentage sign). I would like to do this via setNumberFormat.
However a format token like "0.00", "#,##" etc result in output like "4.238.007.139.4743.425" which is not at all what I want. I somewhat suspect a part of the problem might be that my document is in German, with a comma as decimal delimiter, and the number from the API returned has a decimal point (or I might be overlooking something simple, wich is just as likely).
So, can I use setNumberFormat, and what format token do I have to use to turn "42.380071394743425" into "42,38%" ?
I am using the build-in App service. I do not have problems with other types of KPIs, just percentage values like bounceRate.
var viewId = "<myViewId>"
var options = {};
options['max-results'] = 1;
metric = "ga:bounceRate"; // actually this is passed in as a function parameter
// formatDate is a wrapper that calls Utilities.formatDate
var startDate = formatDate(pDate, 'yyyy-MM-dd');
var endDate = formatDate(pDate, 'yyyy-MM-dd');
var report = Analytics.Data.Ga.get(viewId, startDate, endDate, metric, options);
.....
token = [];
// format is passed in as a function parameter to fit the metric
switch(format) {
case("percentage"):
token.push(["0.00%"]);
break;
default:
token.push(["0.00"]); // tried different options to no avail
break;
}
sheet.getRange(<row>,<col>).setValue(report.rows).setNumberFormats(token);
As I said the code itself is working fine if the API returns unformatted numbers (so I don't think the problem is in the code), but I can't get the bounceRate to display the way I want.
Thank you for your time.
Select Format > Number > More Formats > Custom number formats... and type ##.##"%".
Or you can set the number format by GAS the same way.
var range = sheet.getActiveRange();
range.setNumberFormat('##.##"%"');
This is US locale based. You may change the format string according to your spreadsheet's locale(File > Spreadsheet settings...). As you can see in this documentation, the format is dependant on the spreadsheet's locale.