Can someone one help me make this work:
I have a Checkbox for a non-repeated array. If checkbox is checked to remove duplicates it works fine, but if I uncheck remove duplicates, the checkbox still removes duplicates.
I want to make it work in such a way that if (remove duplicates) checkbox is not checked, extract all emails without removing duplicates.
Thanks.
You were just a couple lines off... when you go to output the emails you need to check for the field that determines if you should use all the emails or the unique (not repeated) emails:
<script type="text/javascript">
function findEmail() {
var email = "No email address detected";
var a = 0;
var ingroup = 0;
var separator = document.extractor.sep.value;
var groupby = Math.round(document.extractor.groupby.value);
var outputEmails = [];
if (separator == "new") separator = "\n";
if (separator == "other") separator = document.extractor.othersep.value;
//match the email pattern in large text pasted in textarea.
var rawemail = document.extractor.rawdata.value.match(/([a-zA-Z0-9._-]+#[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
var norepeat = new Array();
if (rawemail) {
for (var i=0; i<rawemail.length; i++) {
var repeat = 0;
// Check for repeated emails routine
for (var j=i+1; j<rawemail.length; j++) {
if (rawemail[i] == rawemail[j]) {
repeat++;
}
}
// Create new array for non-repeated emails
if (repeat == 0) {
norepeat[a] = rawemail[i];
a++;
}
}
// For output, use all or unique (non-repeated) emails?
outputEmails = document.extractor["non-repeated"].checked ? norepeat : rawemail;
if( document.extractor["sortbox"].checked ) {
outputEmails = outputEmails.sort();
}
email = "";
// Join emails together with separator
for (var k = 0; k < outputEmails.length; k++) {
if (ingroup != 0) email += separator;
email += outputEmails[k];
ingroup++;
// Group emails if a number is specified in form. Each group will be separate by new line.
if (groupby) {
if (ingroup == groupby) {
email += '\n\n';
ingroup = 0;
}
}
}
}
// Return array length
var count = norepeat.length;
// Print results
document.extractor.count.value = count;
document.extractor.rawdata.value = email;
}
</script>
JSFiddle example: https://jsfiddle.net/jimbo2150/ucvLtsts/21/
Related
I have three text prompts and want to validate them as a group, requiring the user to input value in one or more prompts before proceeding.
For e.g. I have First Name, Last Name and Student ID fields and want to group these together such that the user has to input value in at-least one prompt before proceeding. Here is what I have so far, but it is not recognizing the value in second and third fields.
var report = cognos.Report.getReport('_THIS_');
var fName = oCR.prompt.getControlByName('FirstName');
var lName = oCR.prompt.getControlByName('LastName');
var studentId = oCR.prompt.getControlByName('StudentID');
var prompts = [fName ,lName ,studentId];
var i = 0;
var promptsLength = prompts.length;
for ( i = 0; i < promptsLength ; i++) {
prompts[i].setValidator(validate);
}
function validate() {
var result = false;
for ( i = 0; i < promptsLength; i++) {
if (prompts[i].getValues().length > 0) {
result = true;
}
if (prompts[i] != this) {
prompts[i].checkData();
}
}
return result;
}
I am trying to highlight duplicate rows in my sheet by checking for the same email address entered under the 'Email Address' column.
I have some code (below) that does this - it looks for duplicate rows based on repeated values under 'Email Address' and highlights them red. However, once I revisit the sheet, manually remove the duplicate row and rerun the script, the same row is highlighted again. Why is this happening and what can I do to ensure that when I update the sheet, the (now) unique row is not highlighted again?
function findDupes() {
var CHECK_COLUMNS = [3];
var sourceSheet = SpreadsheetApp.getActiveSheet();
var numRows = sourceSheet.getLastRow();
var numCols = sourceSheet.getLastColumn();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var newSheet = ss.insertSheet("FindDupes");
for (var i = 0; i < CHECK_COLUMNS.length; i++) {
var sourceRange = sourceSheet.getRange(1,CHECK_COLUMNS[i],numRows);
var nextCol = newSheet.getLastColumn() + 1;
sourceRange.copyTo(newSheet.getRange(1,nextCol,numRows));
}
var dupes = false;
var data = newSheet.getDataRange().getValues();
for (i = 1; i < data.length - 1; i++) {
for (j = i+1; j < data.length; j++) {
if (data[i].join() == data[j].join()) {
dupes = true;
sourceSheet.getRange(i+1,1,1,numCols).setBackground("crimson");
sourceSheet.getRange(j+1,1,1,numCols).setBackground("crimson");
}
}
}
ss.deleteSheet(newSheet);
if (dupes) {
Browser.msgBox("Possible duplicate(s) found. Please check for repeat attendees.");
} else {
Browser.msgBox("No duplicates found.");
}
};
I want to be able to run the script again once I have manually removed the rows and have it reflect the updated nature of the sheet.
Try this:
Sorry, but there were so many things I couldn't understand why you were doing them that I find it easier just to show you how I'd do it.
function findAndHighlightDupesInColumn(col) {
var col=col||3;//I think you wanted to check column 3
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();//gets all data
var uA=[];//this is the array that hold all unique values
for(var i=1;i<vA.length;i++) {//assumes one header row
if(uA.indexOf(vA[i][col-1])==-1) {//if it's unique then put it in uA
uA.push(vA[i][col-1]);
}else{//if it's not unique then set background color
sh.getRange(i+1,1,1,sh.getLastColumn()).setBackground('crimson');
}
}
}
The following code will remove duplicates in column 3:
This method assumes that the first occurrence of any row is the row that you wish to keep. All other duplicate rows are deleted.
function removeColumnDupes(col) {
var col=col||3
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var uA=[];
var d=0;
for(var i=1;i<vA.length;i++) {
if(uA.indexOf(vA[i][col-1])==-1) {
uA.push(vA[i][col-1]);
}else{
sh.deleteRow(i+1-d++);
}
}
}
Try adding this before the for loops. It will turn all the rows into white, and then the rest of your code will turn the duplicates red:
sourceSheet.getRange(2,1,numRows,numCols).setBackground("white");
Also, you can add an onEdit() function to check for duplicates in real time, when you add or edit an email address:
function onEdit(e){
if (e.range.getColumn() == 3){
var sourceSheet = SpreadsheetApp.getActiveSheet();
var numRows = sourceSheet.getLastRow();
var numCols = sourceSheet.getLastColumn();
var data = sourceSheet.getRange("C2:C"+numRows).getValues();
var editedCell = e.value;
for (var i = 0; i < data.length;i++){
if (editedCell == data[i] && (i + 2) != e.range.getRow()){
sourceSheet.getRange(e.range.getRow(),1,1,numCols).setBackground("crimson");
sourceSheet.getRange(i+2,1,1,numCols).setBackground("crimson");
}
}
}
}
I am currently using the code below to create a single-column search for an HTML table on a website. At the moment, when I type something in to the search bar, the code returns every row that has content that contains the thing I searched for anywhere within it. For example (I'm using this for movie ratings), when I type "G" in to the search bar, I get back everything rated G, but also everything rated PG or PG-13. Is there a way that I can adapt this code to return only results that are exact matches for my search? In other words, is there a way to change things so that when I search for "G" (or "g"), I only get back my G-rated movies and not anything rated PG or PG-13?
Thank you!
The Current Code:
<script type="text/javascript">
function searchRows(tblId) {
var tbl = document.getElementById(tblId);
var headRow = tbl.rows[0];
var arrayOfHTxt = new Array();
var arrayOfHtxtCellIndex = new Array();
for (var v = 0; v < headRow.cells.length; v++) {
if (headRow.cells[v].getElementsByTagName('input')[0]) {
var Htxtbox = headRow.cells[v].getElementsByTagName('input')[0];
if (Htxtbox.value.replace(/^\s+|\s+$/g, '') != '') {
arrayOfHTxt.push(Htxtbox.value.replace(/^\s+|\s+$/g, ''));
arrayOfHtxtCellIndex.push(v);
}
}
}
for (var i = 1; i < tbl.rows.length; i++) {
tbl.rows[i].style.display = 'table-row';
for (var v = 0; v < arrayOfHTxt.length; v++) {
var CurCell = tbl.rows[i].cells[arrayOfHtxtCellIndex[v]];
var CurCont = CurCell.innerHTML.replace(/<[^>]+>/g, "");
var reg = new RegExp(arrayOfHTxt[v] + ".*", "i");
if (CurCont.match(reg) == null) {
tbl.rows[i].style.display = 'none';
}
}
}
}
</script>
firstly use toUpperCase()
then you can just use === if you only want to distinguish G, PG, PG-13, R, NC-17, you dont
I thought this would be easier, but running into a weird issue.
I want to split the following:
theList = 'firstword:subwordone;subwordtwo;subwordthree;secondword:subwordone;thirdword:subwordone;subwordtwo;';
and have the output be
firstword
subwordone
subwordtwo
subwordthree
secondword
subwordone
thirdword
subwordone
subwordtwo
The caveat is sometimes the list can be
theList = 'subwordone;subwordtwo;subwordthree;subwordfour;'
ie no ':' substrings to print out, and that would look like just
subwordone
subwordtwo
subwordthree
subwordfour
I have tried variations of the following base function, trying recursion, but either get into infinite loops, or undefined output.
function getUl(theList, splitOn){
var r = '<ul>';
var items = theList.split(splitOn);
for(var li in items){
r += ('<li>'+items[li]+'</li>');
}
r += '</ul>';
return r;
}
The above function is just my starting point and obviously doesnt work, just wanted to show what path I am going down, and to be shown the correct path, if this is totally off base.
It seems you need two cases, and the difference between the two is whether there is a : in your string.
if(theList.indexOf(':') == -1){
//Handle the no sublist case
} else {
//Handle the sublist case
}
Starting with the no sublist case, we develop the simple pattern:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
//Add your element to your list
}
Finally, we apply that same pattern to come up with the implementation for the sublist case:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
if(element.indexOf(':') == -1){
//Add your simple element to your list
} else {
var innerElements = element.split(':');
//Add innerElements[0] as your parent element
//Add innerElements[1] as your child element
//Increment i until you hit another element with ':', adding the single elements each increment as child elements.
//Decrement i so it considers the element with the ':' as a parent element.
}
}
Keep track of the current list to add items to, and create a new list when you find a colon in an item:
var baseParent = $('ul'), parent = baseParent;
$.each(theList.split(';'), function(i, e) {
if (e.length) {
var p = e.split(':');
if (p.length > 1) {
baseParent.append($('<li>').append($('<span>').text(p[0])).append(parent = $('<ul>')));
}
parent.append($('<li>').text(p[p.length - 1]));
}
});
Demo: http://jsfiddle.net/Guffa/eWQpR/
Demo for "1;2;3;4;": http://jsfiddle.net/Guffa/eWQpR/2/
There's probably a more elegant solution but this does the trick. (See edit below)
function showLists(text) {
// Build the lists
var lists = {'': []};
for(var i = 0, listKey = ''; i < text.length; i += 2) {
if(text[i + 1] == ':') {
listKey = text[i];
lists[listKey] = [];
} else {
lists[listKey].push(text[i]);
}
}
// Show the lists
for(var listName in lists) {
if(listName) console.log(listName);
for(var j in lists[listName]) {
console.log((listName ? ' ' : '') + lists[listName][j]);
}
}
}
EDIT
Another interesting approach you could take would be to start by breaking it up into sections (assuming text equals one of the examples you gave):
var lists = text.match(/([\w]:)?([\w];)+/g);
Then you have broken down the problem into simpler segments
for(var i = 0; i < lists.length; i++) {
var listParts = lists[i].split(':');
if(listParts.length == 1) {
console.log(listParts[0].split(';').join("\n"));
} else {
console.log(listParts[0]);
console.log(' ' + listParts[1].split(';').join("\n "));
}
}
The following snippet displays the list depending on your requirements
var str = 'subwordone;subwordtwo;subwordthree;';
var a = []; var arr = [];
a = str;
var final = [];
function split_string(a){
var no_colon = true;
for(var i = 0; i < a.length; i++){
if(a[i] == ':'){
no_colon = false;
var temp;
var index = a[i-1];
var rest = a.substring(i+1);
final[index] = split_string(rest);
return a.substring(0, i-2);
}
}
if(no_colon) return a;
}
function display_list(element, index, array) {
$('#results ul').append('<li>'+element+'</li>');
}
var no_colon_string = split_string(a).split(';');
if(no_colon_string){
$('#results').append('<ul><ul>');
}
no_colon_string.forEach(display_list);
console.log(final);
working fiddle here
Hi I am trying to compare two arrays to each other and then hide a list element if any of the values match.
One array is tags that are attached to a list item and the other is user input.
I am having trouble as I seem to be able to cross reference one user input work and can't get multiple words against multiple tags.
The amount of user input words might change and the amount of tags might change. I have tried inArray but have had no luck. Any help would be much appreciated. See code below:
function query_searchvar() {
var searchquery=document.navsform.query.value.toLowerCase();
if (searchquery == '') {
alert("No Text Entered");
}
var snospace = searchquery.replace(/\s+/g, ',');
event.preventDefault();
var snospacearray = snospace.split(',');
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
//alert(searchtags);
var searcharray = searchtags.split(',');
//alert(searcharray);
var searchtrue=-1;
for(var i = 0, len = searcharray.length; i < len; i++){
if(searcharray[i] == searchquery){
searchtrue = 0;
break;
}
}
if (searchtrue == 0) {
$(this).show("normal");
}
else {
$(this).hide("normal");
}
});
}
Okay so I've tried to implement the code below but have had no luck. It doesn't seem to check through both arrays.
function query_searchvar()
{
var searchquery=document.navsform.query.value.toLowerCase();
if(searchquery == '')
{alert("No Text Entered");
}
var snospace = searchquery.replace(/\s+/g, ' ');
event.preventDefault();
var snospacearray = snospace.split(' ');
alert(snospacearray[1]);
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
alert(searchtags);
var searcharray = searchtags.split(' ');
alert(searcharray[0]);
jQuery.each(snospacearray, function(key1,val1){
jQuery.each(searcharray,function(key2,val2){
if(val1 !== val2) {$(this).hide('slow');}
});
});
});
}
Working code:
function query_searchvar()
{
var searchquery=document.navsform.query.value.toLowerCase();
if(searchquery == '')
{alert("No Text Entered");
}
var queryarray = searchquery.split(/,|\s+/);
event.preventDefault();
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
//alert(searchtags);
var searcharray = searchtags.split(',');
//alert(searcharray);
var found = false;
for (var i=0; i<searcharray.length; i++)
if ($.inArray(searcharray[i], queryarray)>-1) {
found = true;
break;
}
if (found == true )
{
$(this).show("normal");
}
else {
$(this).hide("normal");
}
});
}
var snospace = searchquery.replace(/\s+/g, ',');
var snospacearray = snospace.split(',');
Note that you can split on regular expressions, so to the above would equal:
var queryarray = searchquery.split(/,|\s+/);
To find whether there is an item contained in both arrays, use the following code:
var found = searcharray.some(function(tag) {
return queryarray.indexOf(tag) > -1;
});
Although this will only work for ES5-compliant browsers :-) To support the others, use
var found = false;
for (var i=0; i<searcharray.length; i++)
if ($.inArray(searcharray[i], queryarray)>-1) {
found = true;
break;
}
In plain js, without jQuery.inArray:
var found = false;
outerloop: for (var i=0; i<searcharray.length; i++)
for (var j=0; j<queryarray.length; j++)
if (searcharray[i] == queryarray[j]) {
found = true;
break outerloop;
}
A little faster algorithm (only needed for really large arrays) would be to sort both arrays before running through them linear.
Here's psuedo code that should solve your problem.
get both arrays
for each item in array 1
for each element in array 2
check if its equal to current element in array 1
if its equal to then hide what you want
An example of this coude wise would be
jQuery.each(array1, function(key1,val1){
jQuery.each(array2,function(key2,val2){
if(val1 == val2) {$(your element to hide).hide();}
});
});
If there's anything you don't understand please ask :)