Match only if word is contained within constraints, Regex - regex

I am struggling with finding the regex to find a word that must be between two others.
in simple, my constraints are:
must begin with the word line con
must end with the next appearence of the word line
between these two must have the word session-timeout
may also contain other words between line con and line.
I wish to match on any block of text starting with line con and ending with the next instance of the word line, however I need them to only match if the word session-timeout is between them.
bonus points if you can tell me how to match for any number larger than 10 after session-timeout (eg. session-timeout 12 would match)
an example of where I would want it to match is:
line con 0
session-timeout 14
stopbits 1
line aux 0
stopbits 1
line vty 0 4
However, this should not match
line con 0
session-timeout 8
stopbits 1
line aux 0
stopbits 1
line vty 0 4
session-timeout 13
line vty 0 5
so far I have the regex expression (line con)(\s|\S)+?(session-timeout ){1}([0-9])(\s|\S)+?(line), however if it does not match a session-timeout within the terms, it simply ignores the first line, which is where I want it to stop looking.
Any help would be massivley appreciated!

You can use
(line con)(?:(?!line con)[\s\S])+?(session-timeout\s+)([1-9][0-9]+)[\s\S]+?(line)
See the regex demo. Details:
(line con) - Group 1: line con string
(?:(?!line con)[\s\S])+? - any char, one or more occurrences but as few as possible, that does not start line con char sequence
(session-timeout\s+) - Group 2: session-timeout string and one or more whitespaces
([1-9][0-9]+) - Group 3: a number from 10 and larger (if you want to allow any leading zeros, append 0* before [1-9])
[\s\S]+? - any one or more chars, as few as possible
(line) - Group 4: line.
Adjust the capturing groups as per your requirements.

Related

Match each group separately followed by a dash

I have some markdown files where I've been using two spaces as tabs instead of four. For correct markdown syntax it should be four spaces, so I am trying to do a find and replace in each of the files.
I can match the double spaces, but when I attempt to only match the groups preceding a dash, it doesn't match what I need.
# List in Markdown
- List Item
  - List Item
    - List Item
      - List Item
  - List Item
    - List Item- List Item
If I use / {2}/mg, it matches each group of 2 spaces separately.
https://regex101.com/r/v1qF15/1
But I only want to replace the spaces that precede a dash. The problem I'm having is that when I add grouping and the dash, all instances of double spaces before a dash is one match instead of individual matches.
/(?: {2})+(?=-)/mg
https://regex101.com/r/VqvrP8/1
Match 1: The set of 2 spaces on line 1
Match 2: The set of 4 spaces on line 2
Match 3: The set of 6 spaces on line 3
But what I really want is:
Match 1: The set of 2 spaces on line 1
Match 2: The first set of 2 spaces on line 2
Match 3: The second set of 2 spaces on line 2
Match 4: The first set of 2 spaces on line 3
I think I'm doing something wrong with my positive look behind or my grouping, but I can't figure out how to fix it.
Assuming that your (multi-line) input string is stored in variable $str:
$str -replace '(?: {2})+(?=-)', '$&$&'
In your simple case, it's sufficient to know the combined length of the two-space multiples that matched, allowing you to in effect double them simply by referring to what was matched ($&) twice in the substitution expression.

Invalid lookbehind pattern

I am simply trying to take the following text:
Password length (length ordered)
5 = 1 (0.37%)
6 = 1 (0.37%)
7 = 1 (0.37%)
8 = 157 (58.58%)
9 = 55 (20.52%)
10 = 33 (12.31%)
11 = 12 (4.48%)
12 = 6 (2.24%)
13 = 2 (0.75%)
And find every new line that exists between Password Length and \n\n. Here's what I was currently doing
data[/(?<=Password length)(.*?)(?=\n\n)/m]
but that captures (length ordered) in the first line.
I have tried to do something like this:
44] pry(main)> data[/(?<=Password length.*?\n)(.*?)(?=\n\n)/m]
(eval):2: invalid pattern in look-behind: /(?<=Password length.*?\n)(.*?)(?=\n\n)/m
To basically capture everything after Password length up to the new line, but as you can see above I get an error about the invalid pattern in look-behind.
What should I be doing instead of this to fix this?
You can use
data[/Password length.*\R(?m:(.*?))\R{2}/, 1]
See the Rubular demo. Details:
Password length - a literal string
.* - the rest of the line
\R - a line break sequence
(?m:(.*?)) - An inline modifier group where . matches any char including line break chars, capturing group 1 matching any zero or more chars but as few as possible
\R{2} - double line break sequence.
The 1 argument returns the value inside the first capturing group only (see the str[regexp, capture] → new_str or nil reference).
An alternative:
data[/Password length.*\R\K.*(?:\R(?!\R).*)*/]
See this Rubular demo. Details:
Password length.*\R - Password length, the rest of the line and a line break sequence
\K - match reset operator, it removes all text matched so far from the match memory buffer
.* - a line, any zero or more chars other than line break chars as many as possible
(?:\R(?!\R).*)* - zero or more lines that do not end with double line break sequence where \R(?!\R).* matches a line break not immediately followed with another line break sequence, and .* matches the rest of the line.

Notepad++ Search and Replace: delete 3 to 4 numbers after N in each row

I have a text file where almost all the lines start with the letter N followed by 3 or 4 numbers as below
N970 G2 X-1.0591 Y-1.7454 I0. J-.04
N980 G1 Y-1.7554
N990 X-1.0594 Y-1.7666
N1000 Z-.2187
N1010 Y-1.7566
How can I remove the N followed by the 3 or 4 numbers in Notepad++ to look like this? if i need to search twice (once for N### and then again for N####) that is fine also.
G2 X-1.0591 Y-1.7454 I0. J-.04
G1 Y-1.7554
X-1.0594 Y-1.7666
Z-.2187
Y-1.7566
the numbers go from 100-9990 in increments of 10 if that helps
You can use the following regex that should work for your case:
^N[0-9]+\s*(.*)
It will match every line that starts with a capital letter N immediately followed by one or more digits. Matched results will include a single group which will contain the text you are looking for.
Note that whitespaces between the N tags and the actual text will not be matched.
Try it out in this DEMO
Breakdown
^ # Assert position at the start of the line
N # Matches capital letter 'N' literally
[0-9]+ # Matches any digit between 1 and unlimited times
\s* # Matches whitespace between 0 and unlimited times
(.*) # The rest of the text you are looking for
Find/Replace
The regex will match each individual line so you can either select Find Next and then Replace and process your file one line at a time or you can choose Replace All to process the whole file at once.
Substitution line (Replace with:) line should just include the first group ($1) which represents the rest of your text with N-prefix tags trimmed.
Make sure that the Search Mode is set to Regular expression.

Splitting a string into a pattern of commands

I need to take a string of concatenated keyword commands and numbers, and put the commands and the numbers into lists.
Pattern:
{command words} by {number} {command words} by {number} etc...
Input string:
"turn right by 1 turn left by 99 up by 11 left by 28"
I thought I might split on the word " by " but that causes the second group to have the number and the next command (eg. 1 turn left).
Regex:
\sby\s
Desired Output:
turn right by 1
turn left by 99
up by 11
left by 28
Desired Lists:
turn right,turn left,up,left
1,99,11,28
How can I split a long string of commands that follow that pattern?
The text is one big long string with no punctuation. The word by is always followed by a number and the pattern is consistent. The first part may contain one or two keyword commands.
Brief
It seems your strings all share the same structure: word or words by 111 (one or more words, followed by by literally, followed by at least one digit)
Code
See regex in use here
(\w[\w ]*?)\s+by\s+(\d+)
Results
Input
turn right by 1 turn left by 99 up by 11 left by 28
Output
Full Match: turn right by 1
Group 1: turn right
Group 2: 1
Full Match: turn left by 99
Group 1: turn left
Group 2: 99
Full Match: up by 11
Group 1: up
Group 2: 11
Full Match: left by 28
Group 1: left
Group 2: 28
Explanation
(\w[\w ]*?) Capture the following into capture group 1
\w[\w ]*? Any word character, followed by anything in the set [\w ] (any word character or space) any number of times, but as few as possible
\s+by\s+ One or more spaces followed by by literally, followed by one or more spaces.
(\d+) Capture one or more digits into capture group 2

RegEx in Notepad++ w/Find and replace

I have data that looks like this:
1 ,11/10/2015, 1 3
2 ,01/15/2013
3 ,04/10/2015, 5 5
4 ,04/01/2013, 165
5 ,07/01/2016, 311 312
I need to find every instance that looks like lines 1, 3, and 5 and replace the white space in between the 2 sets of digits with a comma so they become like:
1 ,11/10/2015, 1,3
2 ,01/15/2013
3 ,04/10/2015, 5,5
4 ,04/01/2013, 165
5 ,07/01/2016, 311,312
I'm close with this:
[^(^\d{1,3})][[^(\d{1,3})]\s+(\d{1,3})\r
, but it's keeping the 2 sets of digits AND the white space. Need to isolate the finds to just the white space in between the 2 sets of digits. The leading numbers (1-5) are not in my data set. Just included these for readability here.
If there is only one whitespace-separated digit pair per line, you may use
(\d+)\h+(\d+)
and replace with $1,$2.
If you need to define some more context and make the regex replacement safer, consider
,\h*\K(\d+)\h+(\d+)$
Details:
, - a comma
\h* - 0+ horizontal whitespaces
\K - omit all the text matched so far
(\d+) - Group 1: one or more digits
\h+ - 1+ horizontal whitespaces
(\d+) - Group 2: one or more digits
$ - end of line.