I have multi-lines string from git log in variable
and want to replace matched lines with hyper-links
but keep some parts of the original string with Groovy.
Example:
commit 7a1825abc69f1b40fd8eb3b501813f21e09bfb54
Author: Filip Stefanov
Date: Mon Nov 21 11:05:08 2016 +0200
TICKET-1
Test change
Change-Id: I7b4028e504de6c4a48fc34635d4b94ad038811a6
Should look like:
commit 7a1825abc69f1b40fd8eb3b501813f21e09bfb54
Author: Filip Stefanov
Date: Mon Nov 21 11:05:08 2016 +0200
<a href=http://localhost:8080/browse/TICKET-1>TICKET-1</a>
Test change
<a href=http://localhost:8081/#/q/I7b4028e504de6c4a48fc34635d4b94ad038811a6,n,z>Change-Id: I7b4028e504de6c4a48fc34635d4b94ad038811a6</a>
Im pretty bad in Groovy regex dont know how to use grouping or closures so far so good:
mystring.replaceAll(/TICKET-/, "http://localhost:8080/browse/TICKET-")
NOTE:
TICKET {int} and Change-Id {hash} are variables
mystring.replaceAll(/(TICKET-\d++)/, '$1')
.replaceAll(/Change-Id: (I\p{XDigit}++)/, 'Change-Id: $1')
Of course you have to replace the dynamic parts accordingly. Currently it is at least one digit after the TICKET- and an I and then at least one hex digit after the Change-ID:.
Related
I'm writing a playbook for ios upgrade of multiple switches and have most pieces working with exception of the flash free check. Basically, I want to check if there is enough flash space free prior to copying the image.
I tried using the gather facts module but it is not working how I expected:
from gather facts I see this:
"ansible_net_filesystems_info": {
"flash:": {
"spacefree_kb": 37492,
"spacetotal_kb": 56574
This is the check I want to do:
fail:
msg: 'This device does not have enough flash memory to proceed.'
when: "ansible_net_filesystems_info | json_query('*.spacefree_kb')|int < new_ios_filesize|int"
From doing some research I understand that any value returned by a jinja2 template will be a string so my check is failing:
Pass integer variable to task without losing the integer type
The solution suggested in the link doesn't seem to work for me even with ansible 2.7.
I then resorted to store the results of 'dir' in a register and tried using regex_search but can't seem to get the syntax right.
(similar to this :
Ansible regex_findall multiple strings)
"stdout_lines": [
[
"Directory of flash:/",
"",
" 2 -rwx 785 Jul 2 2019 15:39:05 +00:00 dhcp-snooping.db",
" 3 -rwx 1944 Jul 28 2018 20:05:20 +00:00 vlan.dat",
" 4 -rwx 3096 Jul 2 2019 01:03:26 +00:00 multiple-fs",
" 5 -rwx 1915 Jul 2 2019 01:03:26 +00:00 private-config.text",
" 7 -rwx 35800 Jul 2 2019 01:03:25 +00:00 config.text",
" 8 drwx 512 Apr 25 2015 00:03:16 +00:00 c2960s-universalk9-mz.150-2.SE7",
" 622 drwx 512 Apr 25 2015 00:03:17 +00:00 dc_profile_dir",
"",
"57931776 bytes total (38391808 bytes free)"
]
]
Can anyone provide some insight to this seemingly simple task? I just want '38391808' as an integer from the example above (or any other suggestion). I'm fairly new to ansible.
Thanks in advance.
json_query wildcard expressions return a list. The tasks below
- set_fact:
free_space: "{{ ansible_net_filesystems_info|
json_query('*.spacefree_kb') }}"
- debug:
var: free_space
give the list
"free_space": [
37492
]
which neither can be converted to an integer nor can be compared to an integer. This is the reason for the problem.
The solution is simple. Just take the first element of the list and the condition will start working
- fail:
msg: 'This device does not have enough flash memory to proceed.'
when: ansible_net_filesystems_info|
json_query('*.spacefree_kb')|
first|
int < new_ios_filesize|int
Moreover, json_query is not necessary. The attribute spacefree_kb can be referenced directly
- fail:
msg: 'This device does not have enough flash memory to proceed.'
when: ansible_net_filesystems_info['flash:'].spacefree_kb|
int < new_ios_filesize|int
json_query has an advantage : see this example on a C9500 :
[{'bootflash:': {'spacetotal_kb': 10986424.0, 'spacefree_kb': 4391116.0}}]
yes they changed flash: to bootflash:.
The following two regularexpressions give the same output in python 3.7.
"+?" is supposed to be non-greedy
re.findall("\S+?#\S+?","From stephen.marquard#uct.ac.za Sat Jan 5 09:14:16 2008")
re.findall("\S+#\S+","From stephen.marquard#uct.ac.za Sat Jan 5 09:14:16 2008")
Both of these give the same output as:
['stephen.marquard#uct.ac.za']
The +? is non-greedy as expected. Refer https://regex101.com/r/DM4voj/1
If you copy pasted both the commands into your shell or program, you will only get the output of the last command. Try using print statements for both. You should get the desired answers.
import re
print(re.findall("\S+?#\S+?","From stephen.marquard#uct.ac.za Sat Jan 5 09:14:16 2008"))
print(re.findall("\S+#\S+","From stephen.marquard#uct.ac.za Sat Jan 5 09:14:16 2008"))
The result will be as below as expected
['stephen.marquard#u']
['stephen.marquard#uct.ac.za']
I wanted to separate the time and date from this string using REGEX because I feel like it is the only way I can separate it. But I am not really familiar on how to do it maybe someone can help me out here.
The original string: Your item was delivered in or at the mailbox at 3:34 pm on September 1, 2016 in TEXAS, MT 59102
The output i want to achieve/populate:
lv_time = 3:34 pm
lv_date = September 1, 2016
Here's the code I was trying to do but I am only able to cut it like this:
lv_status = Your item was delivered in or at the mailbox at
lv_time = 3
lv_date = :34 pm on September 1, 2016 in TEXAS, MT 59102.
Here's the code I have so far:
DATA: lv_status TYPE string,
lv_time TYPE string,
lv_date TYPE string,
lv_off TYPE i.
lv_status = 'Your item was delivered in or at the mailbox at 3:34 pm on September 1, 2016 in TEXAS, MT 59102.'.
FIND REGEX '(\d+)\s*(.*)' IN lv_status SUBMATCHES lv_time lv_date MATCH OFFSET lv_off.
lv_status = lv_status(lv_off).
You asked for it, here it comes:
\b((1[0-2]|0?[1-9]):([0-5][0-9]) ([AaPp][Mm])) on (January|February|March|April|May|June|July|August|September|October|November|December)\D?(\d{1,2}\D?)?\D?((?:19[7-9]\d|20\d{2})|\d{2})
This accepts time in HH:MM am/pm format, and dates in Jan-Dec, dd 1970-2999.
Each part is captured in its own group.
The demo shows a version that allows abbreviated month names:
Demo
I'm trying to capture some input from the user.
/mon,thu',
/mon',
/mon,thu,wed',
/mon,thu-sun'
/mon,tue-thu,sun'
so the "business logic" is that the user can put any of the following words
mon, tue, wed, thu, fri, sat, sun
and they can either be separated by
- or ,
if they are separated by
-
there can only be one day either side i.e
mon-wed
not
mon-wed-sun
if separated by a
,
then only one of the mon, tue, wed, thu, fri, sat, sun can be either side of it.
Basically
,
represents a specific day and
-
represents a range of days
the closest I have been able to get is:
(\bmon\b|\btue\b|\bwed\b|\bthu\b|\bfri\b|\bsat\b|\bsun\b)
I've come up with this:
(mon|tue|wed|thu|fri|sat|sun)(, ?(mon|tue|wed|thu|fri|sat|sun))*(- ?(mon|tue|wed|thu|fri|sat|sun))?(, ?(mon|tue|wed|thu|fri|sat|sun))*
The idea here is that it matches day(,day)(-day)?(,day)
It matches the following:
mon,thu
mon
mon,thu,wed
mon,thu-sun
mon,tue-thu,sun
mon, tue, wed, thu, fri, sat, sun (even with spaces in ,)
mon-wed
but not:
mon-wed-sun
If you are using a PCRE pattern (or any other regex dialect that supports defines) you might wan't to avoid repeating the weekdays over and over, e.g. using
(?(DEFINE)
(?<weekday>\b(?:mon|tue|wed|thu|fri|sat|sun)\b)
(?<field>(?&weekday)(?:-(?&weekday))?)
)
(?&field)(?:,(?&field))*
in verbose mode. See https://regex101.com/r/ELPd6V/1
Note that this would profit from cleaning up the mess around it first and then applying anchors, currently mon-tue-wed will give you two matches.
This will solve your issue. basically, matching "mon" to "sun" then an optional comma not followed by a - (?:,(?!-))?, followed by a repeating (0 to 1) -(mon to sun).
when the case of mon-sun the optional comma will fail the match, hence it
will skip, allowing the - to succeed.
const logicalRE = /(mon|tue|wed|thu|fri|sat|sun)(?:,(?!-))??(?:-(mon|tue|wed|thu|fri|sat|sun)){0,1}/g;
/* cases */
const tCases = ["mon,thu", "mon", "mon,thu,wed", "mon,thu-sun", "mon,tue-thu,sun", "mon-wed-sun", "mon,-thu"]
tCases.forEach(tCase => {
console.log(tCase.match(logicalRE))
})
demo link: https://regex101.com/r/BcqUye/5
I have been struggling making a regex to extract the information in below divided in 3 part between the ",". Only the first and second sequence (Friday and the date has succeded).
Friday, 26 Apr 2013, 18:30
I hope someone has the experience.
Best regards
Why not simply split the string and trim the excess whitespace of the individual parts? For example, verbosely written in C#:
string input = "Friday, 26 Apr 2013, 18:30";
string[] parts = input.Split(',');
for (int i = 0; i < parts.Length; i++)
{
parts[i] = parts[i].Trim();
}
Console.WriteLine(parts[0]); // "Friday"
Console.WriteLine(parts[1]); // "26 Apr 2013"
Console.WriteLine(parts[2]); // "18:30"
If you really want to use a regular expression for this, ^(.*),(.*),(.*)$ should work:
string input = "Friday, 26 Apr 2013, 18:30";
Regex regex = new Regex("^(.*),(.*),(.*)$", RegexOptions.Singleline);
Match match = regex.Match(input);
Console.WriteLine(match.Groups[1].Value.Trim()); // "Friday"
Console.WriteLine(match.Groups[2].Value.Trim()); // "26 Apr 2013"
Console.WriteLine(match.Groups[3].Value.Trim()); // "18:30"
Adding appropriate error checking is left as an exercise for the reader.
The following Regex expression is matching this whole part :
, 18:30
I hope someone has the experience.
Best regards
,+\s[0-9]+:[0-9]+ \r*.*
But yeah, that's kind of ultra specific to this ", Hour:Minuts [...]" format. You should do a split if you're using PHP or the equivalent in your language.
I think what you really want is something like this:
from datetime import datetime
s="Friday, 26 Apr 2013, 18:30"
d=datetime.strptime(s, "%A, %d %b %Y, %H:%M")
d
Out[7]: datetime.datetime(2013, 4, 26, 18, 30)
See the strptime and date format docs for details :)
Edit: sorry, I was somehow assuming you were using Python. Other languages have similar idioms though, e.g. PHP's date_parse, C#'s DateTime.Parse, etc.
You didn't specify a language so I'm going to answer this with a standard REGEX approach.
(?<=(^|,\s+)).+?(?=(,|$)) Will work for you.
Let me break up what it's doing.
(?<=(^|,\s+) - Look ahead for the start of a string or a comma followed by whitespace, but don't include it in the match. All matches must have this in front of them.
.+? - Grab all characters, but don't be greedy.
(?=(,|$)) - Look behind for the end of string or a comma. All matches must have this behind them.
When ran on your test case of Friday, 26 Apr 2013, 18:30, I get 3 matches:
Friday
26 Apr 2013
18:30
Like m01's answer, you could try this approach with C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
namespace TestDate
{
class Program
{
static void Main(string[] args)
{
string dateString = "Friday, 26 Apr 2013, 18:30"; // Modified from MSDN
string format = "dddd, dd MMM yyyy, HH:mm";
DateTime dateTime = DateTime.ParseExact(dateString, format, CultureInfo.InvariantCulture);
Console.WriteLine(dateTime);
Console.Read();
}
}
}
This will print out the localized date and time that is configured on the user's machine. For me it printed out 4/16/2013 6:30:00 PM.