Stacked IFs Google Sheets Apps Script - if-statement

New to Google Apps Script. Could someone tell me to to write stacked IFs in Apps Script.
I want to create a custom function that calculates the total sixteenths in a custom feet-inches-sixteens format.
The format is different depending on the length of the string. 1=1', 12=12',508 = 5 1/2", 1604 = 16 1/4", etc...and in order to convert to feet-inches-sixteen I have to calculate the total 16ths first.
Any help is appreciated.

Your question is a little hard to understand, but I think you have values in sheets represented as 1' 3 1/2" (1 ft, 3.5 in) which you'd like to convert to sixteenth-inch units.
The following function should do what you want:
function SIXTEENTHS(string) {
var regex = /^\s*([0-9]*(?=\'))?\'?\s*([0-9]+(?![0-9]))?\s*([0-9]+\/[0-9]+)?\"?\s*$/;
var parsed = string.match(regex);
if (!parsed) {
return 'Bad input';
}
var inches = (parsed[1] | 0) * 12; // Parse feet
inches += (parsed[2] | 0); // Parse inches
if (parsed[3]) {
inches += (parsed[3].split('/').reduce((a, b) => a/b)); // Parse fractions
}
return inches*16;
}
Parsing the string is a little tricky, but you can see what the regex is doing and test it at Regex 101.

Related

Input Formatter Regex for simple mathematical calculation in Flutter/Dart

I want to ensure valid input on my text field where user can key in simple math expression for numbers up to 2 d.p such as "1.10 + 3.21 x 0.07". I am doing this through the adding regex to the input formatter constructor in the TextField class.
Following the regex example for 2 d.p here, I modified the code for my text field input formatter to include operators:
String dp = (decimalRange != null && decimalRange > 0)
? "([.][0-9]{0,$decimalRange}){0,1}"
: "";
String num = "($dp)|([0-9]{1,4}$dp)";
_exp = new RegExp(
"^($num){0,1}[-+x/]{0,1}($num){0,1}[-+x/]{0,1}($num){0,1}\$");
I am able to achieve "1.10 + 3.21 x 0.07", however, the user can also type invalid value into the textfield such as "1...10", "1.10 + 3..21". Any advice to improve the Regex above would be greatly appreciated!
Note that I also limit the user to key in a maximum of 3 decimal numbers. so "(2d.p)(operator)(2d.p)(operator)(2d.p)is the maximum limit.

Remove operations using regex [duplicate]

This question already has answers here:
How to find sum of integers in a string using JavaScript
(3 answers)
Closed 3 years ago.
I am getting a string back "1+2" and would like to remove the "+" and then add the numbers together.
Is this possible using Regex? So far I have:
let matches = pattern.exec(this.expression);
matches.input.replace(/[^a-zA-Z ]/g, "")
I am now left with two numbers. How would I add together?
"this.a + this.b"
Assuming the string returned only has '+' operation how about:
const sum = str.split('+').reduce((sumSoFar, strNum) => sumSoFar + parseInt(strNum), 0);
You cannot add two numbers using regex.
If what you have is a string of the form "1+2", why not simply split the string on the + symbol, and parseInt the numbers before adding them?
var str = "1+2";
var parts = str.split("+"); //gives us ["1", "2"]
console.log(parseInt(parts[0]) + parseInt(parts[1]));
If you don't always know what the delimiter between the two numbers is going to be you could use regex to get your array of numbers, and then reduce or whatever from there.
var myString = '1+2 and 441 with 9978';
var result = myString.match(/\d+/g).reduce((a,n)=> a+parseInt(n),0);
console.log(result); // 1 + 2 + 441 + 9978 = 10422
*Edit: If you actually want to parse the math operation contained in the string, there are a couple of options. First, if the string is from a trusted source, you could use a Function constructor. But this can be almost as dangerous as using eval, so it should be used with great caution. You should NEVER use this if you are dealing with a string entered by a user through the web page.
var myFormula = '1+2 * 441 - 9978';
var fn = new Function('return ' + myFormula);
var output = fn();
console.log(myFormula, ' = ', output); //1+2 * 441 - 9978 = -9095
A safer (but more difficult) course would be to write your own math parser which would detect math symbols and numbers, but would prevent someone from injecting other random commands that could affect global scope variables and such.

Regex to match comma separated value with last 3 digits

I was trying to have the value as 456,987,214.
But For me it is coming like without comma.
Here is my code, Did i mistake anything
const string price = "^\\d{3},\\d{3},\\d{3}$";
string pricelist = query.price.ToString();
string price1 = "";
if (System.Text.RegularExpressions.Regex.IsMatch(pricelist.ToString(), price))
{
price1 = query.price.ToString();
}
I noticed it, it is number what you intended to format why not using angular built-in formatting feature like: {{price | number}}
Online Demo
If you want to format this with C# then you can format it using .Net built-in formatters like:
double value = 1234567890;
Console.WriteLine(value.ToString("#,#", CultureInfo.InvariantCulture));
// outputs 1,234,567,890
Try this simple Method:
Just pass your value like this ,
double value = double.Parse(query.price.ToString());
string price1= value.ToString("#,#", CultureInfo.InvariantCulture);
Output will be like 123,456,789
Try this simple method: Just pass your value like this, then you will get the output as you want.
double value = double.Parse(query.price.ToString());
string price1= value.ToString("#,#", CultureInfo.InvariantCulture);
Output will be like 123,456,789

Matching algorithm or regular expression?

I have a huge log file with different types of string rows, and I need to extract data in a "smart" way from these.
Sample snippet:
2011-03-05 node32_three INFO stack trace, at empty string asfa 11120023
--- - MON 23 02 2011 ERROR stack trace NONE      
For instance, what is the best way to extract the date from each row, independent of date format?
You could make a regex for different formats like so:
(fmt1)|(fmt2)|....
Where fmt1, fmt2 etc are the individual regexes, for yor example
(20\d\d-[01]\d-[0123]\d)|((?MON|TUE|WED|THU|FRI|SAT|SUN) [0123]\d [01]\d 20\d\d)
Note that to prevent the chance to match arbitrary numbers I restricted year, month and day numbers accordingly. For example, a day number cannot start with 4, neither can a month number start with 2.
This gives the following pseudo code:
// remember that you need to double each backslash when writing the
// pattern in string form
Pattern p = Pattern.compile("..."); // compile once and for all
String s;
for each line
s = current input line;
Matcher m = p.matcher(s);
if (m.find()) {
String d = m.group(); // d is the string that matched
....
}
Each individual date pattern is written in () to make it possible to find out what format we had, like so:
int fmt = 0;
// each (fmt) is a group, numbered starting with 1 from left to right
for (int i = 1; fmt == 0 && i <= total number of different formats; i++)
if (m.group(i) != null) fmt = i;
For this to work, inner (regex) groups must be written (?regex) so that they do not count as capture-groups, look at updated example.
If you use Java, you may want to have a look at Joda time. Also, read this question and related answers. I think Joda DateTimeFormat should give you all the flexibility that you need to parse the various date/time format of your log file.
A quick example:
String dateString = "2011-04-18 10:41:33";
DateTimeFormatter formatter =
DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime dateTime = formatter.parseDateTime(dateString);
Just define a String[] for the formats of you date/time, and pass each element to DateTimeFormat to get the corresponding DateTimeFormatter. You can use regex just separate date strings from other stuff in the log lines, and then you can use the various DateTimeFormatters to try and parse them.

Does anyone know of a reg expression for uk date format

Hi does any one know a reg ex for a uk date format e.g. dd/mm/yyyy.
The dd or mm can be 1 character e.g. 1/1/2010 but the year must always be 4 characters.
Thanks in advance
^\d{1,2}/\d{1,2}/\d{4}$
will match 1/1/2000, 07/05/1999, but also 99/77/8765.
So if you want to do some rudimentary plausibility checking, you need
^(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/\d{4}$
This will still match 31/02/9999, so if you want to catch those, it's getting hairier:
^(?:(?:[12][0-9]|0?[1-9])/0?2|(?:30|[12][0-9]|0?[1-9])/(?:0?[469]|11)|(?:3[01]|[12][0-9]|0?[1-9])/(?:0?[13578]|1[02]))/\d{4}$
But this still won't catch leap years. So, modifying a beast of a regex from regexlib.com:
^(?:(?:(?:(?:31\/(?:0?[13578]|1[02]))|(?:(?:29|30)\/(?:0?[13-9]|1[0-2])))\/(?:1[6-9]|[2-9]\d)\d{2})|(?:29\/0?2\/(?:(?:(1[6-9]|[2-9]\d)(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:0?[1-9]|1\d|2[0-8])\/(?:(?:0?[1-9])|(?:1[0-2]))\/(?:(?:1[6-9]|[2-9]\d)\d{2}))$
will match
1/1/2001
31/5/2010
29/02/2000
29/2/2400
23/5/1671
01/1/9000
and fail
31/2/2000
31/6/1800
12/12/90
29/2/2100
33/3/3333
All in all, regular expressions may be able to match dates; validating them is not their forte, but if they are all you can use, it's certainly possible. But looks horrifying :)
Regex is not the right tool for this job.
It is very difficult (but possible) to come up with the regex to match a valid date. Things like ensuring Feb has 29 days on leap year and stuff is not easily doable in regex.
Instead check if your language library provides any function for validating dates.
PHP has one such function called checkdate :
bool checkdate ( int $month , int $day , int $year)
\b(0?[1-9]|[12][0-9]|3[01])[/](0?[1-9]|1[012])[/](19|20)?[0-9]{2}\b
Match :
1/1/2010
01/01/2010
But also invalid dates such as February 31st
^\d{1,2}/\d{1,2}/\d{4}$
In braces there is min and max char count. \d means digit, ^ start, and $ end of string.
\b(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d
This wont validate the date, but you can check for format
I ran into the similar requirements.
Here is the complete regular expression along with Leap Year validation.
Format: dd/MM/yyyy
(3[01]|[12]\d|0[1-9])/(0[13578]|10|12)/((?!0000)\d{4})|(30|[12]\d|0[1-9])/(0[469]|11)/((?!0000)\d{4})|(2[0-8]|[01]\d|0[1-9])/(02)/((?!0000)\d{4})|
29/(02)/(1600|2000|2400|2800|00)|29/(02)/(\d\d)(0[48]|[2468][048]|[13579][26])
It can be easily modified to US format or other EU formats.
edited:
(3[01]|[12]\d|0[1-9])/(0[13578]|10|12)/((?!0000)\d{4})|(30|[12]\d|0[1-9])/(0[469]|11)/((?!0000)\d{4})|(2[0-8]|[01]\d|0[1-9])/(02)/((?!0000)\d{4})|29/(02)/(1600|2000|2400|2800|00)|29/(02)/(\d\d)(0[48]|[2468][048]|[13579][26])
There are two things you want to do, which in my view are best considered separately
1) You want to make sure that the date is a real, actual date.
For example the 2019-02-29 isn't a real date whereas 2020-02-29 is a real date because 2020 is a leap year
2) You want to check that the date is in the correct format (so dd/mm/yyyy)
The second point can be done easily enough with a simple RegEx, plenty of examples of that.
To complicate matters, if you ask Firefox if 2019-02-29 is a real date, it'll return NaN, which is what you'd expect.
Chrome, on the other hand will say it is a real date and give you back the 1st of March 2019 - which will validate
Chrome, will also accept a single digit number as a proper date too for some strange reason, feed it "2" and it'll give you full date from 2001 back - which will validate
So first step is to create a function which attempts to decipher a date (no matter the format) and works cross-browser to return a boolean indicating if the date is valid or not
function validatableDate(value)
{
Date.prototype.isValid = function()
{ // An invalid date object returns NaN for getTime() and NaN is the only
// object not strictly equal to itself.
return this.getTime() === this.getTime();
};
minTwoDigits = function(n)
{ //pads any digit less than 10 with a leading 0
return (parseInt(n) < 10 ? '0' : '') + parseInt(n);
}
var valid_date = false;
var iso_array = null;
// check if there are date dividers (gets around chrome allowing single digit numbers)
if ((value.indexOf('/') != -1) || (value.indexOf('-') != -1)) { //if we're dealing with - dividers we'll do some pre-processing and swap them out for /
if (value.indexOf('-') != -1) {
dash_parts = value.split('-');
value = dash_parts.join("/");
//if we have a leading year, we'll put it at the end and work things out from there
if (dash_parts[0].length > 2) {
value = dash_parts[1] + '/' + dash_parts[2] + '/' + dash_parts[0];
}
}
parts = value.split('/');
if (parts[0] > 12) { //convert to ISO from UK dd/mm/yyyy format
iso_array = [parts[2], minTwoDigits(parts[1]), minTwoDigits(parts[0])]
} else if (parts[1] > 12) { //convert to ISO from American mm/dd/yyyy format
iso_array = [parts[2], minTwoDigits(parts[0]), minTwoDigits(parts[1])]
} else //if a date is valid in either UK or US (e.g. 12/12/2017 , 10/10/2017) then we don't particularly care what format it is in - it's valid regardless
{
iso_array = [parts[2], minTwoDigits(parts[0]), minTwoDigits(parts[1])]
}
if (Array.isArray(iso_array)) {
value = iso_array.join("-");
var d = new Date(value + 'T00:00:01Z');
if (d.isValid()) //test if it is a valid date (there are issues with this in Chrome with Feb)
{
valid_date = true;
}
//if the month is Feb we need to do another step to cope with Chrome peculiarities
if (parseInt(iso_array[1]) == 2) {
month_info = new Date(iso_array[0], iso_array[1], 0);
//if the day inputed is larger than the last day of the February in that year
if (iso_array[2] > month_info.getDate()) {
valid_date = false;
}
}
}
}
return valid_date;
}
That can be compressed down to
function validatableDate(t) {
Date.prototype.isValid = function () {
return this.getTime() === this.getTime()
}, minTwoDigits = function (t) {
return (parseInt(t) < 10 ? "0" : "") + parseInt(t)
};
var a = !1,
i = null;
return -1 == t.indexOf("/") && -1 == t.indexOf("-") || (-1 != t.indexOf("-") && (dash_parts = t.split("-"), t = dash_parts.join("/"), dash_parts[0].length > 2 && (t = dash_parts[1] + "/" + dash_parts[2] + "/" + dash_parts[0])), parts = t.split("/"), i = parts[0] > 12 ? [parts[2], minTwoDigits(parts[1]), minTwoDigits(parts[0])] : (parts[1], [parts[2], minTwoDigits(parts[0]), minTwoDigits(parts[1])]), Array.isArray(i) && (t = i.join("-"), new Date(t + "T00:00:01Z").isValid() && (a = !0), 2 == parseInt(i[1]) && (month_info = new Date(i[0], i[1], 0), i[2] > month_info.getDate() && (a = !1)))), a
}
That gets you a cross-browser test as to whether the date can be validated or not and it'll read & decipher dates in formats
yyyy-mm-dd
dd-mm-yyyy
mm-dd-yyyy
dd/mm/yyyy
mm/dd/yyyy
Once you've validated the date is a real, proper one you can then test the format with a regex. So for UK dd/mm/yy
function dateUK(value) {
valid_uk_date=false;
valid_date=validatableDate(value);
if(valid_date && value.match(/^(0?[1-9]|[12][0-9]|3[01])[\/](0?[1-9]|1[012])[\/]\d{4}$/))
{ valid_uk_date=true;
}
return valid_uk_date;
}
You then know that the date is a real one and that it's in the correct format.
For yyyy-mm-dd format, you'd do:
function dateISO(value) {
valid_iso_date=false;
valid_date=validatableDate(value);
if(valid_date && value.match(/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/))
{ valid_iso_date=true;
}
return valid_iso_date;
}
It depends how thorough you want to be of course, for a rough check of format sanity a RegEx may be enough for your purposes. If however you want to test if the date is a real one AND if the format is valid then this will hopefully help point you along the way
Thanks