This one may be a bit specialized, but here goes anyway:
Page for reference: http://greg-j.com/icvm/anticartel/search-results.html
Plugin for reference: http://tablesorter.com/
If you look at the last two columns for "Total Fines", you'll see the currency output includes $x.xxx billions and $x.xxx millions. The built-in currency parser does not account for this format. The plugin, fortunately, allows for you to write your own parser. However, I'm not getting anywhere.
See if this works, I haven't tested it:
$.tablesorter.addParser({
id: 'monetary',
'is': function(s) {
return false;
},
format: function(s) {
var i = s.split('$').join('');
var suffixes = [
{name:'thousand', mult: 1000},
{name:'million', mult: 1000000},
{name:'billion', mult: 1000000000},
{name:'trillion', mult: 1000000000000}
];
for (var j in suffixes) {
if (i.indexOf(' '+suffixes[j].name) != -1) {
i = i.split(' '+suffixes[j].name).join('');
val = parseFloat(i) * suffixes[j].mult;
}
}
return val;
},
type: 'numeric'
});
$("#cartels").tablesorter({
widgets: ['zebra'],
sortList: [[0,0]],
headers: {
4: {
sorter:'monetary'
},
5: {
sorter:'monetary'
}
}
});
Can you post the code you've tried?
It looks like what they are doing in the example you posted is assigning each word with a number representation, and then sorting by that:
return s.toLowerCase().replace(/good/,2).replace(/medium/,1).replace(/bad/,0);
So in your case one way might be to replace million with the correct number of zeros and the same for billion. So essentially $1 million gets evaluated to $1,000,000 as far as the parser is concerned.
return s.toLowerCase().replace(/million/,000000).replace(/billion/,000000000);
So s is evaluating to $1000000 once the replace function is evaluated.
Just a thought. Not sure if it works, but it might get you on the right track.
Related
My code:
<th class="sorter-shortDate">Date</th>
$('table').tablesorter({dateFormat: "yyyymmdd"});
Sorting is working on numbers, but it is not working on dates,
My date format is y-m-d H:i,
I also tried to add custom parser:
$.tablesorter.addParser({
id: "customDate",
is: function(s) {
return false;
//use the above line if you don't want table sorter to auto detected this parser
//else use the below line.
//attention: doesn't check for invalid stuff
//2009-77-77 77:77:77.0 would also be matched
//if that doesn't suit you alter the regex to be more restrictive
//return /\d{1,4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}/.test(s);
},
format: function(s) {
s = s.replace(/\-/g," ");
s = s.replace(/:/g," ");
s = s.replace(/\./g," ");
s = s.split(" ");
return $.tablesorter.formatFloat(new Date(s[0], s[1]-1, s[2], s[3]).getTime()+parseInt(s[6]));
},
type: "numeric"
});
Can anyone help me please?
There's a minor bug in the shortDate parser; it replaces all . with a / while converting the date into something the built-in JS date parser can understand (e.g. 2009-12-31 08:09:10.1 becomes 12/31/2009 08:09:10/1 - that last decimal place getting changed into a slash is breaking everything.
You can get around this by modifying the short date parser's regular expression - demo
$.tablesorter.regex.shortDateReplace = /-/g;
$(function() {
$('table').tablesorter({
theme: 'blue',
dateFormat: 'yyyymmdd'
});
});
Since I could not make .toFixed(2) to work I designed my own piece of code to add desired decimal digits after the "." by simple joining two strings with + sign.
While Browser.msgBox outputs the 2 strings joined correctly as "1.00",
it seems like getRange.setValue outputs only the first of the 2 strings as "1" :(
function myFunction() {
var ss_calc = SpreadsheetApp.openById("1cFt0DbnpWGHquKk4ijxdKhwkaF8GhumWDWjTpHuSXbQ");
var sheet_calc = ss_calc.getSheetByName("Calcs");
var ss_source = SpreadsheetApp.openById("1gXeXmiw9EnzQXaiE7H8_zrilE2zyotlSuuIS8X9IxfQ");
var sheet_source = ss_source.getSheetByName("Farmah");
var decDig = ""; var strDec = ""; var impVal = "";
impVal = sheet_source.getRange(12,7).getValue().toString();
if (JSON.stringify(impVal).indexOf(".")>-1)
{ if (JSON.stringify(impVal).split(".")[1].length < 2 )
{
if (JSON.stringify(impVal).split(".")[1].length < 1)
{
decDig = "00";
}
else
{
decDig = "0";
}
}
}
else
{
decDig = ".00";
}
var strDec = impVal.toString() + decDig.toString();
Browser.msgBox(JSON.stringify(impVal).indexOf(".")+ "\\n" +
impVal.toString()+ "\\n" +
decDig+ "\\n" +
strDec);
sheet_calc.getRange(1,1).setValue(strDec);
}
From sheet_calc.getRange(1,1).setValue(strDec); I am expecting to get output "1.00" but I get only "1" :(
What am I missing?
Here are the links to google spreadsheets ( anyone with the link can edit :)
(above code has to be triggered manually by script editor in the first spreadsheet here under):
https://docs.google.com/spreadsheets/d/1cFt0DbnpWGHquKk4ijxdKhwkaF8GhumWDWjTpHuSXbQ/edit?usp=sharing
https://docs.google.com/spreadsheets/d/1gXeXmiw9EnzQXaiE7H8_zrilE2zyotlSuuIS8X9IxfQ/edit?usp=sharing
You want to put the value of 1.00 to a cell "A1".
If my understanding is correct, how about this modification? I think that the reason of your issue is that the value by putting by setValue() is converted to the number. By this, 1 is shown. In order to put the value as 1.00, I think that there are 3 patterns. Please select one of them for your situation.
Pattern 1:
In this pattern, from your question, the value is put as a string using setNumberFormat("#").
From:
sheet_calc.getRange(1,1).setValue(strDec);
To:
sheet_calc.getRange(1,1).setNumberFormat("#").setValue(strDec);
Pattern 2:
In this pattern, from your question, the format of cell is set using setNumberFormat("0.00").
From:
sheet_calc.getRange(1,1).setValue(strDec);
To:
sheet_calc.getRange(1,1).setNumberFormat("0.00").setValue(strDec);
Pattern 3:
In this pattern, from the script of your shared Spreadsheet, When decDig is ".00", the format is set.
From:
sheet_calc.getRange(x+6,c).setValue(strDec);
To:
var range = sheet_calc.getRange(x+6,c);
if (decDig) {
range.setNumberFormat("0.00").setValue(strDec); // or setNumberFormat("#")
} else {
range.setValue(strDec);
}
Reference:
setNumberFormat(numberFormat)
If I misunderstood your question and this was not the result you want, I apologize.
From sheet_calc.getRange(1,1).setValue(strDec); I am expecting to get output "1.00" but I get only "1" :(
Google Sheets, as well as other spreadsheet apps, have an automatic data type assignation, so things that look as numbers are converted to Google Sheets number data type, etc.
You could prepend an ' to force that a value be treated as text or you could set the number format in such way that numbers are displayed with two decimals. The cell formatting could be applied in advance, i.e., by using the Google Sheets UI commands or you could use Apps Script to set the format for you.
I am using the table sorter plugin to sort my tables.
I want to be able to catch date column in format:
dd/MM/yyyy HH:mm
and then sort them correctly (for this I have to switch days with years).
Here is what I've so far:
ts.addParser({
id: "hebreLongDate",
is: function (s) {
return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4} d{1,2}:d{1,2}/.test(s);
}, format: function (s, table) {
var c = table.config;
s = s.replace(/\-/g, "/");
// reformat the string in ISO format
s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
return $.tablesorter.formatFloat(new Date(s).getTime());
}, type: "numeric"
});
It does not work.
I would appreciate any help, especially if it comes with an explantation on the meaning of the correct regex.
Thanks,
Omer
The parser doesn't really validate the date. The is function only detects if the format matches the pattern for the format function which is why it is just easier to make it return false and manually set the parser for a column using the headers option:
headers: {
1: { sorter: "hebreLongDate" }
},
The is function above is requiring a HH:mm within the pattern, so if the first table cell in the column doesn't match, it ignores that parser. So either way it would be better to manually set the parser.
Anyway, here is how I would write the parser you are describing (demo):
$.tablesorter.addParser({
id: "hebreLongDate",
is: function(s) {
return false;
},
format: function(s, table, cell, cellIndex) {
s = s
// replace separators
.replace(/\s+/g," ").replace(/[\-.,]/g, "/")
// reformat dd/mm/yyyy to yyyy/mm/dd
.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$2/$1");
return s ? $.tablesorter.formatFloat( (new Date(s).getTime() || ''), table) : s;
},
type: "numeric"
});
As for explaining the regex, there isn't that much of a difference between the code above and what you have in your question. The biggest difference is that the above code ensures that only one space exists between the date and time and that the date can be separated by a slash, dash, period, comma or space (i.e. 1-1-2000, 1 1 2000 etc).
Update: if you want to have this parser be autodetected, then use the following is regex (updated demo). But it is important to note, that this regex cannot distinguish mmddyyyy from ddmmyyyy so it will always detect ddmmyyyy. To override this, set the header sorter option to "shortDate":
is: function(s) {
// testing for ##-##-####, so it's not perfect; time is optional
return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})/).test((s || '').replace(/\s+/g," ").replace(/[\-.,]/g, "/"));
},
I have created a table and sorted it with tablesorter. One of the columns is a mix of letters and numbers (chr1, chr2, ..., chr10, ... , chrM). I want this column to be sorted as if it were only numbers (from 1 to 22 and then X, Y and M in this order).
I have created my own parser and it works but just for some rows. Then, I find another block of rows which are correctly sorted followed by some other blocks. I do not know why this blocks are formed.
The code is here. Maybe with a smaller table it would work properly, because of that I have shown a big one.
Thanks in advance!
Try this parser (demo)
$.tablesorter.addParser({
// set a unique id
id: 'chrom',
is: function (s) {
// return false so this parser is not auto detected
return false;
},
format: function (s) {
// format your data for normalization
return s.toLowerCase()
.replace('chr', '')
.replace('x', '97')
.replace('y', '98')
.replace('m', '99');
},
// set type, either numeric or text
type: 'numeric'
});
I have a table like this I'd like to sort :
| Name | Case |
| John | X-123/08 P|
| Bob | X-123/09 |
| Dylan | X-45/10 |
I want to sort the Case colum by case's year then case's number knowing that the format is always "X-(1 to 4 digits for case's number)/(case's year on 2 digits) (sometimes some text)". It's possible that after the year's case I have some text but it shoud be ignored for sorting.
I am using tablesorter jQuery's plugin and I am struggling to add a custom parser for this.
Thanks for your help !
EDIT : Here's what I'm trying to do :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
// format your data for normalization
return s.replace(/^X-\d{1,4}\/(\d{2}).*$/, '$1') + ('000' + s.replace(/^X-(\d{1,4})\/\d{2}.*$/, '$1')).substr(-4);
},
// set type, either numeric or text
type: 'text'
});
It's working great until I encounter a case with 2 digits which is then ranked greater than a 3 digits one and I don't understand why ...
"X-458/09 P" is sorted smaller than "X-48/09" . I'll try some debug to see what really happens.
EDIT 2 : Also tried the second answer :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
var m = s.match(/X\-(\d+)\/(\d{2}).*$/);
var affaire = m[1];
var year = m[2];
return year + '000' + affaire;
},
// set type, either numeric or text
type: 'text'
});
The result seems to be the same as the first one... I really can't understand why it sucks. Why tablesorter thinks that 488 000 10 is smaller than 49 000 10 ?!
I think you can use:
$.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
// return false so this parser is not auto detected
return false;
},
format: function(s) {
// format your data for normalization
return s.replace(/^X-\d{1,4}\/(\d{2}).*$/, '$1') + ('000' + s.replace(/^X-(\d{1,4})\/\d{2}.*$/, '$1')).slice(-4);
},
// set type, either numeric or text
type: 'text'
});
EDIT:
Maybe you already tried something like this with type: 'numeric'; I'm not sure, but this may fail because parseInt('09') === 0.
EDIT 2:
Changed to reflect sorting by year, then case number.
You can use a regex to get the 2 values you're after, for example:
var columnVal = "X-123/08";
var m = columnVal.match(/X\-(\d+)\/(\d{2})$/);
var case = m[1];
var year = m[2];
After trying multiple things this one seems to work perfectly well :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
var m = s.match(/X\-(\d+)\/(\d{2}).*$/);
var caseVar = '000' + m[1];
var size = caseVar.length;
caseVar= caseVar.substr(size-4, 4);
var year = m[2];
return jQuery.tablesorter.formatFloat(year + caseVar);
},
// set type, either numeric or text
type: 'numeric'
});
I did some research and it appears that the substr function with a negative value doesn't work on all browser (I'm using IE because my application must be IE compliant). I think that's the cause of my previous problems and that's why Spiny's solution wasn't working for me.
Thanks anyway to all of you for your precious help !