So, I have a spinEdit that should display the year and month in this format yyyyMM. I am using RegEx to mask the value to that format but when I want to increment from say 201212 to 201301, it fails and displays 20121. The RegEx I am using looks like this
([0-9][0-9][0-9][0-9])(0[1-9])|(1[0-2])
The issue is that incrementing the value (add 1 to month) isn't incrementing the year field when the month is at 12. The same happens in reverse where decreasing the value (minus 1 month) isn't decreasing the year, 201301 - 1 takes it to 2013. Is there a way to fix this using just RegEx?
I think it is possible, but not fully regex solution, you need to have linux and bash available (personally I find the date function in bash ve) I had to get the date formats (string) in a filename and compare it to a date in a script. Below is the code snippet:
#!/bin/bash
#yyyymm you got after regex
inputdate = 201307
#value you want to subtract
x = 8
#outputdate should return you 201211
outputdate = $(date -d "$inputdate01 -$x month" +"%Y%m")
I believe there may be a way, however that is far to complicated for its worth in a practical situation. So by keeping things simple, it is not possible.
Related
I have question. I am trying to prepare date regex comparmission. The problem is month and day if its one digit it can be present as 03 or 3 for both month and day. For instance possible values:
2015/03/27 or 2015/4/12 or 2015/07/05 or 2015/2/2 or 2015/02/3
What i did so far is:
^(?<Month>\d(0([0-1]|1[0-2])|([1-12])){1,2})/(?<Day>\d{1,2})/(?<Year>(?:\d{4}|\d{2}))$
I started to make now for month:
(?<Month>\d(0([0-1]|1[0-2])|([1-12])){1,2})
(0([0-1]|1[0-2])|([1-12])){1,2})
so {1,2} - because can be one digit or two for instance (12, 2, 02)
0([0-1]|1[0-2]) | ([1-12])) - because can be two digits or one
somehow i cant figure it into the final version.
Can you help me out?
Using just \d, you might end up with fake dates, like 12/67/4567.
Also, your input has another date format: Year/Month/Day.
I suggest using this regex for your input format:
^(?<Year>(?:19|20)\d{2})\/(?<Month>0?[1-9]|1[0-2])\/(?<Day>3[01]|0?[1-9]|[12][0-9])$
See demo
Optional 0s are made possible due to the ? quantifier after 0.
If it is for .NET, you do not have to escape /s.
To validate the date, use the classes and methods of the programming environment you are using. Here is an example in C#:
var resultFromRegex = "2015/03/27";
DateTime validDate;
var isValid = DateTime.TryParseExact(resultFromRegex, "yyyy/MM/dd", new System.Globalization.CultureInfo("en-US"), System.Globalization.DateTimeStyles.None, out validDate);
Can anyone think of a better way to write this? It works but it is a little ugly.
Input data looks like this: 125100001
The first two numbers are the year, next two are the week number, and last 5 are the serial. I want to validate that the week number is not over 52 for an angular input[number] pattern option. Basically just to leverage the $error field :)
So here it is:
^\d\d(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-2]){1}\d{5}$
Use this:
^(\d{2})([0-4][1-9]|[1-5]0|5[12])(\d{5})$
Notes
The first set of parentheses (0[1-9]|1[0-2]) validates the month: 01-12
The second set of parentheses ([0-4][1-9]|[1-5]0|5[12]) validates the week: 01-52
If you wish, you can retrieve each component with groups 1, 2 and 2
Just for the week part:
[0-4]\d|5[0-2]
so the entire regex would be:
^\d\d([0-4]\d|5[0-2])\d{5}$
In GAS, using the .replace(), Is it possible to match any term within a long text string that is at least 5 consecutive ALL CAPS characters (may have 1 space in there) and prefix it with a string, such as ][? There may be multiple matches within the text string, so I want to insert markers that begin and end a phrase beginning with an ALLCAPS category.
An example of a similar type of text would be this (structurally similar, but with other sensitive data):
"VACATION: Approved by Supervisor - Frequency 1-3 times per year; duration not to exceed 5 days. SICK LEAVE: Approved by Supervisor - Frequency up to 8 per year, no more than 5 days consecutively without MD excuse. FMLA FEDERAL: Approved by HR - Frequency as needed, must be approved at least 14 days in advance, or within 24 hours of employee's identified need."
I have learned, through Serge, how to replace globally, which was a big help, but the more I research regexp's, the more confusing it gets. I tried substituting the all caps regexp for a specific term, but failed. I think that I could go through and extract all of the all caps regexp's and use them in a replace with multiple values, but it seems that would be a very long way around.
Is it possible, in a couple of lines to make the above text look like this:
"][VACATION: Approved by Supervisor - Frequency 1-3 times per year; duration not to exceed 5 days. ][SICK LEAVE: Approved by Supervisor - Frequency up to 8 per year, no more than 5 days consecutively without MD excuse. ][FMLA FEDERAL: Approved by HR - Frequency as needed, must be approved at least 14 days in advance, or within 24 hours of employee's identified need."
My intention is to then split on the ] Which would mean that new cells would start with the all caps term, and end with ]. I have the code to convert the text to an array (there are lots of entries), then use .replace() to find and replace within the array, and to set the values back into the sheet, but I just don't know if there is a way to either prefix (my research says lookback isn't possible in GAS), or to pick up the allcaps value, add the string "][", and put it back.
If this is asking too much, or feels like I haven't included any code, here is the first part that Serge already helped with: Looking for a Google script that will perform CTRL+F replace for a string
Here is the code, as I used it, combining Serge's previous help and the new recommendation. I had to fix some case issues with a term before running the all caps because some people can't follow a template, but it works.
function insertSplitMarkers(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Freq Iso');
var data = sh.getRange(2,1,sh.getLastRow(),sh.getLastColumn()).getValues();// get all data
var regexp = /(([A-Z]\s*){5,})/g;
for(var n=0;n<data.length;n++){
for(var m=0;m<data[0].length;m++){
if(typeof(data[n][m])=='string'){ // if it is a string
data[n][m]=data[n][m].replace(/Interventions/g,'INTERVENTIONS');// use the regex replace with /g parameter meaning "globally"
data[n][m]=data[n][m].replace(regexp, "][$1");
}
}
}
Logger.log(data);
sh.getRange(2,1,data.length,data[0].length).setValues(data);
}
It looks like this will do what you want although as is, it will also pick out aoAOEOUE:
var yourString = "VACATION: Approved by Supervisor - Frequency 1-3 times per year; duration not to exceed 5 days. SICK LEAVE: Approved by Supervisor - Frequency up to 8 per year, no more than 5 days consecutively without MD excuse. FMLA FEDERAL: Approved by HR - Frequency as needed, must be approved at least 14 days in advance, or within 24 hours of employee's identified need.";
var regexp = /(([A-Z]\s*){5,})/g;
var newString = yourString.replace(regexp, "][$1");
Logger.log(newString);
#user3169581 I've adjusted your regex slightly to try to eliminate matching whitespace around the desired phrase and ensure you get the whole desired phrase, it will require a little adjustment in the replace:
var regexp = /\b([A-Z\s]{5,})(:)/g
...
data[n][m] = data[n][m].replace(regexp,"][$2$3")
Link to regex101 with working matching here: http://regex101.com/r/rD5kS9
HTH
EDIT: for some reason the existing answer wasn't showing up for me when I started this response. Forgive the redundancy.
I need a regex for date string which validates
YYYY:MM:DD:HH
YYYY:MM:DD:HH:mm
YYYY:MM:DD:HH:mm:ss
means all 3 formats are valid.
Can someone help me with this ?
I have
d\d\d\d:(0\d|1[012]):([012]\d|3[01]):([01]\d|2[0-3])$ YYYY:MM:DD:HH
^\d\d\d\d:(0\d|1[012]):([012]\d|3[01]):([01]\d|2[0-3]):[0-5]\d$ YYYY:MM:DD:HH:MM
^\d\d\d\d:(0\d|1[012]):([012]\d|3[01]):([01]\d|2[0-3]):[0-5]\d:[0-5]\d$ YYYY:MM:DD:HH:MM:SS
These 3 regex and needs to be combine in one
this is your pattern
YYYY:MM:DD:HH(:mm(:ss)?)?
? means 0 or 1 time
you can test it here
I kept your year month day expression d\d\d\d:(0\d|1[012]):([012]\d|3[01]):([01]\d|2[0-3]). Since your hour and minute expressions where the same :[0-5]\d I just required them to appear zero, once or twice with.
The resulting expression is:
^\d\d\d\d:(0\d|1[012]):([012]\d|3[01]):([01]\d|2[0-3])(:[0-5]\d){0,2}$
This expression by francis-gagnon is a slight modification to prevent edge cases where the day or month is expressed as 00.
^\d\d\d\d:(0[1-9]|1[012]):(0[1-9]|[12]\d|3[01]):([01]\d|2[0-3])(:[0-5]\d){0,2}$
If you're looking to also check the date is valid then you could use something like this monster which will test each date position to it's valid and that the time will fit into 24 hour clock:
^(?:(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(:|\/|-|\.)(?:0?2\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(:|\/|-|\.)(?:(?:(?:0?[13578]|1[02])\2(?:31))|(?:(?:0?[13-9]|1[0-2])\2(?:29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\2(?:0?[1-9]|1\d|2[0-8]))))(?::(?:[01]\d|2[0-3]))?(?::[0-5]\d){0,2}$
\d{4}:[0-1][0-9]:[0-3][0-9](?::[0-5][0-9](?::[0-5][0-9])?)?
Does anyone have a regurlar expression available which only accepts dates in the format dd/mm/yy but also has strict checking to make sure that the date is valid, including leap year support?
I am coding in vb.net and am struggling to work this one out.
I don't think the leap year support is doable in a regex without using some ugly regex.
You will have to check the date validity after validating input with the regex.
As hinted by Keeper, you could use the DateTime.ParseExact method to validate your date :
Public Function IsValidDate(ByVal dateString As String) As Boolean
Try
DateTime.ParseExact(dateString, "dd/MM/yy", System.Globalization.CultureInfo.InvariantCulture)
Return True
Catch ex As FormatException
Return False
End Try
End Function
Apart from the fact that such a regex would be a long dirty unmaintainable thing if it existed, you can't even tell for sure if an year in YY format is a leap year or not. 00 is leap if and only if it is a multiple of 400. 2000 was leap, 1900 wasn't.
The following regex makes sure that date is between 01 and 31, month is between 01 and 12 and year is between 1900 and 2099. Delete the (?:19|20) part to make it dd/mm/yy format: then year can be anything from 00 to 99. Do the real validation using standard date-time libraries - use the regex for just client side validations (to save a trip to server - assuming you're doing date-time validation at server), or as a screening test before feeding to the real validator.
^(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/((?:19|20)\d{2})$
It will be hard, or ugly and a maintenance nightmare, or even impossible.
Just do a check in code after Regex validation.
No need to use a regex because there's already a date parsing function: DateTime.ParseExact
I think it is extreamly hard to check whether year leap or not with reqular expression. Please take a look at this article about your problem. Here is a citate from here:
Again, how complex you want to make
your regular expression depends on the
data you are using it on, and how big
a problem it is if an unwanted match
slips through. If you are validating
the user's input of a date in a
script, it is probably easier to do
certain checks outside of the regex.
For example, excluding February 29th
when the year is not a leap year is
far easier to do in a scripting
language. It is far easier to check if
a year is divisible by 4 (and not
divisible by 100 unless divisible by
400) using simple arithmetic than
using regular expressions.
You'd probably be better off just doing the format-validation in regex and handling the date-validation separately.
You're trying to use the regex hammer to solve an eminently non-nail shaped problem.
Would it not be better to extract the numbers using regular expressions, but validate it programatically?
There is no need to verify the format because the "parse" methods will do this for you. the parse will compare all date format strings in DateTimeFormatInfo against the string you pass to the method. The parse-exact method will only compare the specified string against the data format strings you pass to the method.
Imports System.Globalization
Module Sample
Public Function IsValidDateString1(ByVal s As String) As Boolean
Return Date.TryParseExact(s, "dd/MM/yy", CultureInfo.InvariantCulture, DateTimeStyles.None, Nothing)
End Function
Public Function IsValidDateString2(ByVal s As String) As Boolean
Static _dateFormats() As String = New String() {"dd/MM/yy", "d/M/yy", "d/M/yyyy"}
Return Date.TryParseExact(s, _dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, Nothing)
End Function
Public Sub Main()
Debug.WriteLine("single")
Debug.WriteLine(IsValidDateString1("31/12/2001")) 'wrong format
Debug.WriteLine(IsValidDateString1("31/12/01"))
Debug.WriteLine(IsValidDateString1("29/2/08")) '<-be careful
Debug.WriteLine(IsValidDateString1("29/ 2/08")) '<-be careful
Debug.WriteLine(IsValidDateString1("29/02/08"))
Debug.WriteLine(IsValidDateString1("29/02/09")) 'invalide date
Debug.WriteLine("multiple")
Debug.WriteLine(IsValidDateString2("31/12/2001"))
Debug.WriteLine(IsValidDateString2("31/12/01"))
Debug.WriteLine(IsValidDateString2("29/2/08"))
Debug.WriteLine(IsValidDateString2("29/ 2/08")) '<-be careful
Debug.WriteLine(IsValidDateString2("29/02/08"))
Debug.WriteLine(IsValidDateString2("29/02/09")) 'invalid date
End Sub
End Module