I try to parse some xml file, with this code:
function parseXml() {
var url = 'http://www.inpo.ru/documents/pricelists/pricelist.xml';
var xml = UrlFetchApp.fetch(url).getContentText();
var parseregexp = new RegExp (/.*em><no>(\d+)<\/no><title>(.+?)<\/title><price vat="\w+">(\d+.\d+|\d+)<\/price><unit>(.+?)<\/unit><free>(\d+)<\/free>(.|\s)*?<it/g)
var parsedData = '$1 $2 $3 $4 $5 '
var rangeRegex = [];
var Pdata = xml.replace(parseregexp,parsedData)
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
ss.getRange(1, 1).setValue(Pdata)
}
And here is xml fragment:
<item><no>48514</no><title>The workpiece is the rod d 8x150mm P6AM5 HRC 64-66" CNIC"</title><price vat="yes">154.58</price><unit>Pcs</unit><free>59</free><remarks>Used to make an axial tool.
Hardness HRC64-66</remarks><img thumbnail="http://www.inpo.ru/index/I:48528/THUMBNAIL:0.jpg">http://www.inpo.ru/index/I: 48528 / PREVIEW: 0.jpg</img></item><item><no>48515</no><title>The workpiece is the rod d 8x200mm P6AM5 HRC 64-66"CNIC"</title><price vat="Yes">198.24</price><unit>pcs</unit><free>32</free><remarks>Used to make an axial tool.
Hardness HRC64-66</remarks><img thumbnail="http://www.inpo.ru/index/I:48528/THUMBNAIL:0.jpg">http://www.inpo.ru/index/I: 48528 / PREVIEW: 0.jpg</img></item>
And result in Pdata is:
48514 The workpiece is the rod d 8x150mm P6AM5 HRC 64-66" CNIC" 154.58 Pcs 59 48515 The workpiece is the rod d 8x200mm P6AM5 HRC 64-66"CNIC" 198.24 pcs 32
In this example in Pdata I have 1 long string from all regex matches. How I can make an array with 5 columns from all matches? I think to push every match to array with "for" cycle, but dont know how it's mades. Would be pleasefull for any help
Alternate Solution:
Since you are trying to access xml data you can use XMLservice.parser
However there seems to a problem in the fetch call, I was unable to get the whole data (fetch gives a truncated file, perhaps it is timing out, 16mb file) , so I downloaded the data file and uploaded it into google drive.
This file could be used to parse XML data like so:
function parseXml() {
var file = DriveApp.getFileById("Xml File ID") //Get the id of the uploaded file and replace it for "Xml File ID"
var xml = file.getBlob().getDataAsString()
// The below code gave a error for XML parser
/*var url = 'http://www.inpo.ru/documents/pricelists/pricelist.xml';
var options = {
'method' : 'get',
'contentType': 'application/xml',
}
var xml = UrlFetchApp.fetch(url,options).getBlob().getDataAsString()
Logger.log(xml)*/
// End of code with gave an error
var arrayItems = []
var XmlElem = ["no","title","price","unit","free"] //Elements to look for
var document = XmlService.parse(xml);
var RCounter = 0
var groups = document.getRootElement().getChildren(); //GetGroup Element
for(var k = 0; k< groups.length; k++){ // Loop through each group element
var main = groups[k].getChildren() // Get sub groups in each group
for (var j=0 ; j < main.length; j++){ // Loop through each subGroups
var mainChilds = main[j].getChildren() //Get items in each subGroups
for (var l = 0 ; l < mainChilds.length; l++){ // Loop through each items
var items = mainChilds[l].getChildren(); // Get elemetns like "no","title","price","units","free" in each item
arrayItems[RCounter] = []
var total = 0;
for (var i = 0; i < items.length; i++) {
// Logger.log(items[i].getName())
var index = XmlElem.indexOf(items[i].getName()) //Look for items and place the value at corresponding index
if(index != -1)
arrayItems[RCounter][index] = items[i].getValue()
} //End Loope for elements
if(arrayItems[RCounter].length > 0) //in case the array is empty, reuse it
RCounter++
} // End loop for items
} // End loop for sub Groups
} // End loop for Groups
Logger.log(arrayItems)
}
Hope that helps!
Related
I have a UFC database and I'm looking for rematches. Therefore, I need to find the duplicate combinations of names; the combinations that appear more than once. However, since the winner of the first fight could lose the rematch, I need to find duplicates regardless of the order in which they appear.
This is how my database is structured:
database example.
Fighter 1 is the winner and fighter 2 is the loser.
Here is a link to the database (got it from kaggle): https://docs.google.com/spreadsheets/d/19ISNhYFdGzgLZz1x4h2v_Q5Pq0cofw2rkUtwk3xPXGQ/edit?usp=sharing
Feel free to play around with it.
Any ideas on how to solve this?
Here is an example of the result I'd ideally want:
image example
Just a simple highlight over the duplicates.
In order to give you more precise help, it would be helpful if you could give an example of the result you want. As has been said, if there are many duplicates and you mark each group with a different colour, it can be visually confusing.
Anyway, I have written a couple of functions with Apps Script and Spreadsheet Service that you may find useful for your project.
Code 1
With these functions, you will be able to get all fights where two fighters that you previously define have participated:
function main() {
var name1 = 'Conor McGregor'
var name2 = 'Nate Diaz'
var result = findDuplicates(name1, name2)
console.log(result)
}
function findDuplicates(name1, name2) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Ark1')
var lastRow = sheet.getLastRow()
var lastCol = sheet.getLastColumn()
var range = sheet.getRange(1, 1, lastRow, lastCol).getValues()
var result = []
for (var i = 0; i < range.length; i++) {
if (range[i].includes(name1) && range[i].includes(name2)) {
result.push(range[i])
}
}
return result
}
Code 2
With this function, you can add in a third column, the same number for each pair of fighters. This way, it is very easy to change the "add a number" to "paint the cells in a colour".
function findPairs() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Ark2')
var lastRow = sheet.getLastRow()
var lastCol = sheet.getLastColumn()
var range = sheet.getRange(1, 1, lastRow, lastCol).getValues()
var indexToSkip = []
var k = 0
for (var i = 0; i < range.length; i++) {
if (!indexToSkip.includes(i)) {
var match = range[i]
indexToSkip.push(i)
sheet.getRange(i + 1, 3).setValue(k)
for (var j = i + 1; j < range.length; j++) {
if (range[j].includes(match[0]) && range[j].includes(match[1])) {
indexToSkip.push(j)
sheet.getRange(j + 1, 3).setValue(k)
}
}
k = k+1
}
}
}
References:
Apps Script
Spreadsheet Service
I am quite new to Google Script, I'm learning on the job.
I have a range of data as a variable. It's only one column, column F in this case, but there are empty cells between values. I have a working script (got it from here earlier), which only loops through the cells with values in them. So lets say value1 is in F5, value2 is in F13, it's all random and always changing.
I'm trying to get the row number for these values, so that script should give back "5" for value1 and "13" for value2, ideally together with the value itself.
So far, that's what I have and I can not seem to progress further.
var sourceID = "sourceID";
var main = SpreadsheetApp.openById("mainID");
var mainsheet = main.getSheetByName("Lab Data");
var sourcesheet = source.getSheetByName("sheet name");
var dataRange = sourcesheet.getDataRange(); // range full sheet
var values = dataRange.getValues(); // values full sheet
var SWrowss = findCellForSW(); // getting start row from another function
var CQrowss = findCellForCQ(); // getting last row from another function
var noRows = CQrowss - SWrowss; // gets number of rows in range
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues(); // range we need, column F
// get rid of empty cells from range - copied script from stack overflow
var cResult = colss.reduce(function(ar, e) {
if (e[0]) ar.push(e[0])
return ar;
}, []);
Logger.log("cResult: " + cResult); // cResult contains all sub headers - no empty cells
// gets element's position in array
for(var b = 0; b < cResult.length; b++){
var position = b+1;
Logger.log("pos " + position);
} // end for
If you want to know the row number, I would propose you a different approach
Just loop through your values and retrieve the position of the ones that are not empty:
...
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rows = [];
var calues = [];
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
var row = SWrowss+b+1;
rows.push(row);
var value = colss[b][0];
values.push(value);
}
}
...
With the other solution you can build a single object that can do the conversion for you very quickly.
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rvObj={};
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
rvObj[colss[b][0]]=SWrowss+b+1;
}
}
With rvObj now you can get any row with var row = rvObj[value];
I am looking at a table with 2,000-10,000 rows and need to save the content of 50 rows in a txt file, each line in the txt. file should be 1 row. In addition the the delimiter needs to be a "|".
Table given:
A1 T B1 C1 ...
A2 T B2 C2 ...
saved in txt. file like:
A1|T|B1|C1|...
A2|T|B2|C2|...
How do I need to loop through the table to create for 50 rows a new file including the content?
function getTxtFiles(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getSheetByName("Test");
var folderName = 'Test Folder';
var folderID = 'Test Folder ID';
var documentName = 'Test_1.txt'
var folder = DriveApp.getFolderById(folderID);
var data = sheet.getDataRange();
var values = data.getValues();
var rows = "";
for (var a = 0; a < data[a].length; a++) {
for (var i = 0; i < values[i].length; i++) {
for (var j = 0; j < values[i].length; j++) {
if (values[i][j]) {
rows = rows + values[i][j];
}
rows = rows + "|";
}
}
}
var sss = DriveApp.createFile(documentName,rows,MimeType.PLAIN_TEXT);
var file = DriveApp.getFileById(sss.getId());
var parents = file.getParents();
parents.next().removeFile(file);
folder.addFile(file);
}
I would like to achieve that the script is creating from a table with2,000 rows and with 40 columns, 40 x txt. files and each file includes the content of 50 rows, each row as 1 line in the txt. file.
Try the following code:
function txtFileCreator(){
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues(); // will give you all data cells in a 2D array
var text = "";
var count = 0;
var flag = false;
for (var i = 0; i < data.length; i++){
flag = true;
for (var j = 0; j < data[0].length; j++)
text += data[i][j] + " | ";
text += "\n";
if ((i+1) % 50 == 0){
count++;
createF(text, count);
text = "";
flag = false;
}
}
if (flag)
createF(text, ++count);
}
function createF(content, count){
DriveApp.createFile("File " + count, content, MimeType.PLAIN_TEXT);
}
It worked perfectly for me, I tried with a test sheet with your kind of ranges and it creates the right files with just 50 lines each.
Flow:
values is a 2D array. Join the inner array using | and outer array with \n
Use str.match(regex) to get a array of 50 rows each
Create file for each string in the array.
Snippet:
var folder = DriveApp.getFolderById('[OUTPUT_FOLDER_ID]')
values.map(function(row){return row.join('|')})
.join('\n')
.match(/((?:.*\n){50}|(?:[\s\S]+$))/g)
.forEach(function(str,i){ folder.createFile('textFile'+ i, str})
References:
Folder#createFile
String#match
I'm trying to make a spreadsheet to upload products in Prestashop by .csv. Everything works like a charm, but now I need to be able to make some changes in already entered products with the same spreadsheet. The only thing I came up with is to manipulate text strings from a cell into a variable array (after that I'll find a way to go forward).
Firstly I managed to combine about ~100 cells into one cell (which I accomplished with a complicated formula) but now I need the text from this cell to be separated and temporarily stored in an array variable.
This is the formula. It's joining columns in rows with a : separator and then joins those rows with a ; separator and in the end I just needed a number:
=regexreplace(regexreplace(regexreplace(concatenate(arrayformula(if($A$13:$A$50="","",if($C$13:$C$50="","",$A$13:$A$50&":"&$C$13:$C$50&if($D$13:$D$50="","",$D$13:$D$50)&":"&(ROW($A$13:$A$50)-12)&";"))))," :",":"),": ",":"),"\+","-")
This resulted in this text:
Producător:GARMIN:1;Tip:Ceas inteligent:3;Model:Vivomove HR
Premium:4;Culoare:Gold:5;Culoare curea:Light
brown:6;Greutate:56.5g:8;Rezolutie display:64x128:9;Tip
ecran:OLED:10;GPS:Da:15;Bluetooth:Da:16;Durata in regim de asteptare
(ore):168:24;Sensori:Heart RATE, Activity Tracker, Barometric
altimeter, Accelerometer, Smart notifications, Weather, Step counter,
Move bar, Calories burned, Floors climbed, Analog
hands:26;Garanție:24luni:38;
Now I need to separate everything back as it was, but by a code in Apps Script, so that I will be able to manipulate the values separately, but they would still be in a structured form.
It should be something like this (inside a two dimensional variable):
[0][0]Producător [0][1]GARMIN
[1][0]Tip [1][1]Ceas inteligent
[2][0]Model [2][1]Vivomove HR Premium
[3][0]Culoare [3][1]Gold
[4][0]Culoare curea [4][1]Light brown
[5][0]Greutate [5][1]56.5g
[6][0]Rezolutie display [6][1]64x128
[7][0]Tip ecran [7][1]OLED
[8][0]GPS [8][1]Da
[9][0]Bluetooth [9][1]Da
[10][0]Durata in regim de asteptare (ore) [10][1]168
[11][0]Sensori [11][1]Heart RATE, Activity Tracker, Barometric altimeter, Accelerometer, Smart notifications, Weather, Step counter, Move bar, Calories burned, Floors climbed, Analog hands
[12][0]Garanție [12][1]24luni
And now the main part... The next code is breaking with the error Cannot call method "push" of undefined
//var ss = SpreadsheetApp.getActiveSpreadsheet();
//var activeSheet = ss.getActiveSheet();
//var idSpreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1zRsGMoXJzG9oht_pr3Rr24ksPqBzTZIvNcYPUKfphNI/edit#gid=1264546658").getSheetByName("RO").getDataRange().getValues();
//var idToChange = activeSheet.getRange("A12").getValue();
var row = 0;
//var userID = Session.getActiveUser();
var bufferFeatures = [{}];
bufferFeatures = idSpreadsheet[10][29];
var bufferImages = idSpreadsheet[row][27];
//var productRows = bufferFeatures.indexOf(";",0);
var testColumn = [];
var pos = 0; //here is where we start the text string
var del = 0; //here is where we find the ";" delimiter and stop slicing text string
// THIS FOR LOOP WORKS FINE
for (pos = 0; pos < bufferFeatures.length; pos = del) {
del = bufferFeatures.indexOf(";", pos);
testColumn.push(bufferFeatures.slice(pos, del));
del++;
};
var rownr = 0; //current row number.. not really using this variable
var pos1 = 0; //here is where we start the text string
var del1 = 0; //here is where we find the ":" delimiter and stop slicing text string
var columnsAndRows = [];
columnsAndRows.push([]);
var j = 0;
//THIS FOR LOOP GIVES ME TROUBLE
for (var x = 0; x <= testColumn.length; x++) {
for (pos1 = 0; pos1 + 1 < testColumn[x].length; pos1 = pos1) {
del1 = testColumn[j].indexOf(":", del1);
var theSlice = testColumn[j].slice(pos1, del1);
var theStop = testColumn[j].length;
//for some reason, I can't get this code to "push" j=2)
Logger.log("Adding " + theSlice);
columnsAndRows[j].push(theSlice);
del1++;
pos1 = del1;
Logger.log("Added")
}
Logger.log("Next row");
del1 = 0
j++;
//rownr++;
};
You need to declare columnsAndRows[j] as a array too.
columnsAndRows[j] = [];
Using split() would be much easier:
function strToArr(string) {
if (!string) {
var string = "Producător:GARMIN:1;Tip:Ceas inteligent:3;Model:Vivomove HR Premium:4;Culoare:Gold:5;Culoare curea:Light brown:6;Greutate:56.5g:8;Rezolutie display:64x128:9;Tip ecran:OLED:10;GPS:Da:15;Bluetooth:Da:16;Durata in regim de asteptare (ore):168:24;Sensori:Heart RATE, Activity Tracker, Barometric altimeter, Accelerometer, Smart notifications, Weather, Step counter, Move bar, Calories burned, Floors climbed, Analog hands:26;Garanție:24luni:38; "
}
var arr1 = string.substr(0, string.lastIndexOf(";")).split(';'); //split by ;
var arr2 = arr1.map(function(e) { return e.split(':').slice(0,2)}); //split each element of arr1 by : and return only the first two elements
Logger.log(arr2);
return arr2;
}
I am working on a script that, in part, takes an array of names, compares each name to column A in a sheet, and returns with a row matched value in column B. (Like the vLookup command in sheets)
The setup
var ss = SpreadsheetApp.getActiveSpreadsheet();
var clientsSheet = ss.getSheetByName("Clients");
var cRow = clientsSheet.getLastRow();
var cColumn=clientsSheet.getLastColumn();
var cData=clientsSheet.getRange(1,1,cRow,cColumn).getValues(); //create array of client data
The trouble code
//put each client on their own row and add hour
for(i=0; i < client.length; ++i){
var cl = client[i]
//iterate over array of clients (column A) and hours (Column B) to find match and log the number in column B
for(j=0;j<cData.length;++j){
if (cData[j][0]==cl){
var hour = cData[j][1];
}
}
//return the matched values
Logger.log(cl+" - "+hour);
}
The var 'client' is an array that was split from a list of names in a single cell that are separated by commas (see whole code below)
At the moment it works great except that it misses the last element in the array.
for example:
if I have a sheet with two columns and three rows like so:
A 1
B 2
C 3
I would get back
A-1
B-2
C-
It is missing that last piece on the last element - it should be
A-1
B-2
C-3
I am stumped, and I know that it must be some simple little thing.
Any help would be amazing
Thanks!
The Code:
function logClients()
/*
Take data from a google form check box submissions. Check box submissions put all checked answers into a single cell separated by a comma. The function first takes the most recently submitted row, removes unneeded spaces, and splits each element into its own part of an array.
Then, the function compares each clients name in the array to a sheet with other info, such as the default number of hours we meet. It takes the clients name, the date of submission, and the hours, and logs them on a new row in two different sheets, the Hours sheet and the Trans Log sheet.
*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = ss.getSheetByName("Log"); //Raw data from the Google form
var hourSheet = ss.getSheetByName("Hours"); //logged data for my records, separated into individual clients
var transLog = ss.getSheetByName("Trans Log"); // logged data minus "other" catagory
var clientsSheet = ss.getSheetByName("Clients"); //sheet containing all clients names and the typical hours we meet
var lRow = logSheet.getLastRow();
var hRow = hourSheet.getLastRow();
var tRow = transLog.getLastRow();
var cRow = clientsSheet.getLastRow();
var cColumn = clientsSheet.getLastColumn();
var cData = clientsSheet.getRange(1, 1, cRow, cColumn).getValues();
//get list of clients from cell and split it into an array
var Client = logSheet.getRange(lRow, 2).getValue().replace(", ", ","); //remove all spaces after a comma
var client = Client.split(",");
//get "other" information and do the same
var Other = logSheet.getRange(lRow, 5).getValue().replace(", ", ",");
var other = Other.split(",");
//check the date and set to today if nothing else has been entered
var dcell = logSheet.getRange(lRow, 4).getValue();
var date = new Date()
if (dcell == "") {} else if (dcell == "Yesterday") {
date = new Date(date.getTime() - 1 * (24 * 3600 * 1000));
} else {
date = dcell
}
var date = Utilities.formatDate(date, "GMT-8", "MM/dd/yy"); //format date
//put each client on their own row
for (i = 0; i < client.length; ++i) {
var cl = client[i]
var hour = logSheet.getRange(lRow, 3).getValue(); //hours
if (hour == !"") {
break;
}
for (j = 0; j < cData.length; ++j) {
if (cData[j][0] == cl) {
var hour = cData[j][1];
}
}
Logger.log(date + " - " + cl + " - " + hour);
hourSheet.appendRow([date,cl, hour]);
transLog.appendRow([date, cl, hour]);
}
//put each client on their own row
for (i = 0; i < other.length; i++) {
hourSheet.appendRow([date, other[i], getHour(client[i])]);
}
} //end of function
``
This is a code that I have been working on to teach myself Java and Apps-script
Yup, simple mistake.
Not all of the spaces before each name were being removed from the array, so the if statement would skip right over them because they were not a true match