How to match sequences of consecutive Date like characters string in Dart? - regex

I have consecutive characters as date like 20210215 and 14032020
I am trying to convert to date string like 2021.02.15 and 14.03.2020
My first problem is the consecutive characters it is in 2 format type. Like:
1) 20210215
2) 14032020
And my second problem to convert them to date string without changing the format. Like:
1) 2021.02.15
2) 14.03.2020
When I search about regex couldn't find any pattern to convert the above {20210215} consecutive characters examples to date {2021.02.15} string.
What is correct regex pattern to convert both format as I describe above in Dart?
UPDATE-1:
I need to turn this string "20210215" to this "2021.02.15" as a string and not DateTime. Also I need to turn this string "14032020" to this string "14.03.2020". And I don't want to turn to DateTime string.
First I need to detected if the year is in beginning of the string or end of it. Than put dot (.) between the day, month and year string.
UPDATE-2:
this is best I can found but it turns 02 day or month to 2. But I need as it is.
var timestampString = '13022020';//'20200213';
var re1 = RegExp(
r'^'
r'(?<year>\d{4})'
r'(?<month>\d{2})'
r'(?<day>\d{2})'
r'$',
);
var re2 = RegExp(
r'^'
r'(?<day>\d{2})'
r'(?<month>\d{2})'
r'(?<year>\d{4})'
r'$',
);
var dateTime;
var match1 = re1.firstMatch(timestampString);
if (match1 == null) {
var match2 = re2.firstMatch(timestampString);
if (match2 == null) {
//throw FormatException('Unrecognized timestamp format');
dateTime = '00.00.0000';
print('DATE_TIME: $dateTime');
} else {
var _day = int.parse(match2.namedGroup('day'));
var _month = int.parse(match2.namedGroup('month'));
var _year = int.parse(match2.namedGroup('year'));
dateTime = '$_day.$_month.$_year';
print('DATE_TIME(match2): $dateTime');
}
} else {
var _year = int.parse(match1.namedGroup('year'));
var _month = int.parse(match1.namedGroup('month'));
var _day = int.parse(match1.namedGroup('day'));
dateTime = '$_year.$_month.$_day';
print('DATE_TIME(match1): $dateTime');
}
Output:
DATE_TIME: 2020.2.13
But I need to get output as 2020.02.13.
Second is match1 also prints 1302.20.20 But if I remove var match2 section and if format is like 20200213 it works but doesn't print the 0 as I post it above.

You can use
text.replaceAllMapped(RegExp(r'\b(?:((?:19|20)\d{2})(0?[1-9]|1[0-2])(0?[1-9]|[12][0-9]|3[01])|(0?[1-9]|[12][0-9]|3[01])(0?[1-9]|1[0-2])((?:19|20)\d{2}))\b'), (Match m) => m[4] == null ? "${m[1]}.${m[2]}.${m[3]}" : "${m[4]}.${m[5]}.${m[6]}")
The \b(?:((?:19|20)\d{2})(0?[1-9]|1[0-2])(0?[1-9]|[12][0-9]|3[01])|(0?[1-9]|[12][0-9]|3[01])(0?[1-9]|1[0-2])((?:19|20)\d{2}))\b regex matches
\b - a word boundary
(?: - start of a non-capturing group:
((?:19|20)\d{2}) - year from 20th and 21st centuries
(0?[1-9]|1[0-2]) - month
(0?[1-9]|[12][0-9]|3[01]) - day
| - or
(0?[1-9]|[12][0-9]|3[01]) - day
(0?[1-9]|1[0-2]) - month
((?:19|20)\d{2}) - year
) - end of the group
\b - word boundary.
See the regex demo.
See a Dart demo:
void main() {
final text = '13022020 and 20200213 20111919';
print(text.replaceAllMapped(RegExp(r'\b(?:((?:19|20)\d{2})(0?[1-9]|1[0-2])(0?[1-9]|[12][0-9]|3[01])|(0?[1-9]|[12][0-9]|3[01])(0?[1-9]|1[0-2])((?:19|20)\d{2}))\b'), (Match m) =>
m[4] == null ? "${m[1]}.${m[2]}.${m[3]}" : "${m[4]}.${m[5]}.${m[6]}"));
}
Returning 13.02.2020 and 2020.02.13 20.11.1919.
If Group 4 is null, the first alternative matched, so we need to use Group 1, 2 and 3. Else, we join Group 4, 5 and 6 with a dot.

Related

How to detect incomplet date from list and replace with flutter?

Hello I don't find how to detect an incomplet date from listString. I think about regex but don't know how to extract this sequence input.
input=[2022-01-20 20:01, 2022-01-20 21, 2022-01-20 22:25, 2022-01-20 23:01]
Here I tried to match 2022-01-20 21 (it's the only who not have minute)
after match I want to add minute :00 to remove wrong date format
Here is what I search to have
output=[2022-01-20 20:01, 2022-01-20 21:00, 2022-01-20 22:25, 2022-01-20 23:01]
here is what I tried
dateList=[2022-01-20 20:01, 2022-01-20 21, 2022-01-20 22:25, 2022-01-20 23:01];
for (var i = 1; i < dateList.length; i++) {
RegExp regExp = new RegExp(
r"^((?!:).)*$",
);
var match = regExp.firstMatch("${dateList}");
var index = dateList1.indexOf(match);
dateList.replaceRange(index, index + 1, ["$match:00"]);
}
for each index of my stringlist I seach the only who not have : after I found the index who have a problem, and I replace the index with the add :00
problem match return null...
Thank you
I agree that using regular expressions is the way to go here. Detecting a date is relatively simple, you're basically looking for
4-digits dash 2-digits dash 2-digits space 2-digits colon 2-digits
Which, in RegExp language is
\d{4}-\d{2}-\d{2} \d{2}:\d{2}
Now we can detect whether a given String contains a complete datetime. The only thing that's left is to add the trailing minutes when it is missing. Note that you can decide what to add using another regular expression, but this code will just add the minutes, assuming that's always the issue.
List<String> input = ['2022-01-20 20:01', '2022-01-20 21', '2022-01-20 22:25', '2022-01-20 23:01'];
List<String> output = [];
// detect a date + time
RegExp regex = RegExp(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}');
for (String maybeDate in input) {
bool isCompleteDate = regex.hasMatch(maybeDate);
if (isCompleteDate) {
output.add(maybeDate);
} else {
// we want to comlete the String
// in this case, I assume it's always just the minutes missing, but you could use another regex to see which part is missing
output.add(maybeDate + ':00');
}
}
print(output);
Alternatively, you can indeed use negative lookahead to find the missing minutes:
// detects a date and hour, without a colon and two digits (the minutes)
RegExp missingMinutes = RegExp(r'(\d{4}-\d{2}-\d{2} \d{2})(?!:\d{2})');
Which, in case you have a String instead of a List<String> would result in
List<String> input = ['2022-01-20 20:01', '2022-01-20 21', '2022-01-20 22:25', '2022-01-20 23:01'];
String listAsString = input.toString();
RegExp missingMinutes = RegExp(r'(\d{4}-\d{2}-\d{2} \d{2})(?!:\d{2})');
List<RegExpMatch?> matches = missingMinutes.allMatches(listAsString).toList();
for (int i = matches.length - 1; i >= 0; i--) {
// walk through all matches
if (matches[i] == null) continue;
listAsString = listAsString.substring(0, matches[i]!.end) + ':00' + listAsString.substring(matches[i]!.end);
}
print(listAsString);

How do I use reaLline() to find matches in a file using regex and print them out to the console

I am trying to have the user input a class number and name to pull up a list of information on that class I have on a file. I have figured out how to match the information using .toRegex. I can't figure out how to use the users input to find the match they need and not all matching in the file. I am very new to Regnex.
val pattern = """\d+\s+([A-Z]+).\s+(\d+)\s.+\s+\w.+""".toRegex()
val fileName = "src/main/kotlin/Enrollment.txt"
var lines = File(fileName).readLines()// reads every line on the file
do{
print("please enter class name")
var className = readLine()!!
print("please enter class number ")
var classNum = readLine()!!
for(i in 0..(lines.size-1) ){
var matchResult = pattern.find(lines[i])
if(matchResult != null) {
var (className,classNum) = matchResult.groupValues
println("className: $className, class number: $classNum ")
}
}
}while (readLine()!! != "EXIT") ```
example line from file
Name Num
0669 HELP 134 AN CV THING ETC 4.0 4.0 Smith P 001 0173 MTWTh 9:30A 10:30A 23 15 8 4.0
See MatchResult#groupValues reference:
This list has size of groupCount + 1 where groupCount is the count
of groups in the regular expression. Groups are indexed from 1 to
groupCount and group with the index 0 corresponds to the entire
match.
If the group in the regular expression is optional and there were no
match captured by that group, corresponding item in groupValues
is an empty string.
You need
var (_, className,classNum) = matchResult.groupValues
See Kotlin demo:
val lines = "0669 HELP 134 AN CV THING ETC 4.0 4.0 Smith P 001 0173 MTWTh 9:30A 10:30A 23 15 8 4.0 "
val pattern = """^\d+\s+([A-Z]+)\s+(\d+)""".toRegex()
var matchResult = pattern.find(lines)
if(matchResult != null) {
var (_, className,classNum) = matchResult.groupValues
println("className: $className, class number: $classNum ")
}
// => className: HELP, class number: 134
I simplified the regex a bit since find() does not require a full string match to
^\d+\s+([A-Z]+)\s+(\d+)
See the regex demo. Details:
^ - start of string
\d+ - one or more digits
\s+ - one or more whitespaces
([A-Z]+) - Group 1: one or more uppercase ASCII letters
\s+ - one or more whitespaces
(\d+) - Group 2: one or more digits
You need to use a variable in the pattern that you get from the user .readLine()
Use a loop to check each line with another loop checking if the patter is in that line. pattern.containMatchIn()
val className = readLine()!!.toUpperCase()
print("please enter class number ")
val classNum = readLine()!!
val pattern = """\s+\d+\s+$className.\s+$classNum""".toRegex()
for(i in 0..(lines.size-1) ) {
var matchResult = pattern.find(lines[i])
if(matchResult != null ){
if (pattern.containsMatchIn(lines[i])) {
println(lines[i])
}
}
}```

Regex for characters in specific location in string

Using notepad++, how can I replace the -s noted by the carats? The dashes I want to replace occurs every 7th character in the string.
11.871-2-2.737-2.00334-2
^ ^ ^
123456781234567812345678
It's pretty simple since it's only dashes:
(\S*?)-
Begin capture group.............................. (
Find any number of non-space chars... \S*
Lazily until...............................................?
End capture group...................................)
No capture find hyphen...........................-
Demo 1
var str = `11.871-2-2.737-2.00334-2`;
var sub = `$1`;
var rgx = /(\S*?)-/g;
var res = str.replace(rgx, sub);
console.log(res);
"There is a dash (right above 1) that I would like to preserve. This seems to get rid of all the dashes in the string"
The question clearly shows that there isn't a dash at the "1 position", but since there's a possibility that it's possible considering the pattern (n7). Don't have time to break it down, but I can refer you to a proper definition of the meta char \b.
Demo 2
var str = `-11.871-2-2.737-2.00334-2`;
var sub = `$1$2`;
var rgx = /\b[-]{1}(\S*?)-(\S*?)\b/g;
var res = str.replace(rgx, sub);
console.log(res);
Search for ([0-9\.-]{6,6})-
Replace with: $1MY_SEPARATOR

Regex pattern for float or integer and space and word [duplicate]

This question already has answers here:
Regex for a number followed by a word
(3 answers)
Closed 2 years ago.
What could be possible regex pattern for float or integer and space and a word?
Examples:
str = "12.4 count"
OR
str = "12 count"
OR
str = "(12.4 count)"
To match:
float or integer and space and a word
This might be an approach:
\d*\.?\d+ \w+
Explanation
Match zero or more digits \d*
Match an optional dot \.?
Match one or more digits \d+
A literal space
Match any word character one or more times \w+
This regex would work:
([0-9]+([.][0-9]+)? [a-zA-Z]+)
[0-9]+ will match any integer...
...([.][0-9]+)? or float...
...[a-zA-Z]+ followed by a space, and a word (assuming that you only want to match characters from the roman alphabet)
You can use the following regex:
(\d+(\.\d+)? \w+)
var reg = function(str){
return str.match(/(\d+(\.\d+)? \w+)/g);
}
console.log(reg("12.4 count"));
console.log(reg("12 count"));
console.log(reg("(12.4 count)"));
Try this:
var re = /(\d+(\.\d+)?)\s(\w+)/;
var strs = [
"12.4 count",
"12 count",
"(12.4 count)"
]
strs.forEach(
(str) => {
var res = re.exec(str);
console.log('Full Match', res[0]);
console.log('Number', res[1]);
console.log('Word', res[3]);
}
);
This one will give you the the values but only find then once per string.
var re = /(\d+(\.\d+)?)\s(\w+)/g; // Do a global search, more than once per string
var strs = [
"12.4 count. 43.23 mountains. 134 fish.",
"12 count",
"(12.4 count)"
]
strs.forEach(
(str) => {
while(true) {
var res = re.exec(str);
if (res === null) {
break;
}
console.log('Full Match:', res[0]);
console.log('Number:', res[1]);
console.log('Word:', res[3]);
}
}
);
This one will find every match within a string even if there are multiple matches.
/(\d+(\.\d+)?)\s(\w+)/
\d+ = One or more digit
(.\d+)? = Match a . and then one or more digits and the whole thing zero or one times.
\s = Whitespace
\w+ = One ore more Alpha Numeric
The parenthesis are used to create groups so you can pull out the individual sections if you want them

Regex exclude exact digit from digits

Hello my fellow dream builders.
I am parsing time from twitter and I am using this regex:
{
match = /^[1]/.exec(obj.tweetTime);
if(match != null){
time = "1 hour ago";
}
else
{
match = /^[0-9]{1,2}/.exec(obj.tweetTime);
time = match + " hours ago";
}
}
My question is, if there is simpler way to do this? As you can see, I have 2 digits for time. I just want to format my print right. Hour/Hours as you can see.
Is it possible to write only 1 regex and use only 1 conditional bracket?
PS: I am beginner at regex, and I know /^[0-9]{1,2}/ allow numbers from 0 to 99 practically, but as I said it works for my needs, just asking if it is possible to do this properly, since I lack knowledge.
Thank you, much love <3
I would do it like this:
var match = obj.tweetTime.match(/^\d+$/);
if (match) {
var time = match[0] + ' hour' + (match[0] == 1 ? '' : 's') + ' ago';
}
EDIT Turns out the string is formatted! In which case:
var match = obj.tweetTime.match(/^(\d+)([smhd])$/);
if (match) {
var units = { s: 'second', m: 'minute', h: 'hour', d: 'day' },
time = match[1] + ' ' + units[match[2]] + (match[1] == 1 ? '' : 's') + ' ago';
}
To explain the regex:
^ Anchor matches to the beginning of the string
(\d+) Capture one or more digits in first group
([smhd]) Capture s, m, h or d in second group
$ Anchor to end of string