Greedy negative lookbehind (in Swift) - swift

I'm in need of a regular expression that acts like the following:
matches (any part of foo() in the following statement):
foo()
arg: foo()
foo()
(arg: foo()) {}
does not match:
#foo()
I currently have the following, but it has some problems:
^\s*?(?<!#)((\w+?)\()
^\s*? includes any whitespace at the beginning of the line, which means arg: foo() doesn't match the foo() bit. I had to include this to get the # lookbehind working correctly;
(?<!#) is a lookbehind to discard the match if a # before the thing() is matched;
(\w+?)\( matches the part of thething( correctly, only if there's no # before it.
If there's no ^\s*? in the regex, it would be behaving partly correct, but this shouldn't happen. It should rather discard the match entirely (not just for one character):
It has to discard the match entirely if any # is before it, although it must match this correctly: #Mode foo() (the foo() bit, disregarding the #Mode before it).
If there are any tips to help me out, that would be awesome!

Use
(?<![\w#])\w+\(\)
See regex proof.
EXPLANATION
--------------------------------------------------------------------------------
(?<! look behind to see if there is not:
--------------------------------------------------------------------------------
[\w#] any character of: word characters (a-z,
A-Z, 0-9, _), '#'
--------------------------------------------------------------------------------
) end of look-behind
--------------------------------------------------------------------------------
\w+ word characters (a-z, A-Z, 0-9, _) (1 or
more times (matching the most amount
possible))
--------------------------------------------------------------------------------
\( '('
--------------------------------------------------------------------------------
\) ')'

Related

How to match exact string in perl

I am trying to parse all the files and verify if any of the file content has strings TESTDIR or TEST_DIR
Files contents might look something like:-
TESTDIR = foo
include $(TESTDIR)/chop.mk
...
TEST_DIR := goldimage
MAKE_TESTDIR = var_make
NEW_TEST_DIR = tesing_var
Actually I am only interested in TESTDIR ,$(TESTDIR),TEST_DIR but in my case last two lines should be ignored. I am new to perl , Can anyone help me out with re-rex.
/\bTEST_?DIR\b/
\b means a "word boundary", i.e. the place between a word character and a non-word character. "Word" here has the Perl meaning: it contains characters, numbers, and underscores.
_? means "nothing or an underscore"
Look at "characterset".
Only (space) surrounding allowed:
/^(.* )?TEST_?DIR /
^ beginning of the line
(.* )? There may be some content .* but if, its must be followed by a space
at the and says that a whitespace must be there. Otherwise use ( .*)?$ at the end.
One of a given characterset is allowed:
Should the be other characters then a space be possible you can use a character class []:
/^(.*[ \t(])?TEST_?DIR[) :=]/
(.*[ \t(])? in front of TEST_?DIR may be a (space) or a \t (tab) or ( or nothing if the line starts with itself.
afterwards there must be one of (space) or : or = or ). Followd by anything (to "anything" belongs the "=" of ":=" ...).
One of a given group is allowed:
So you need groups within () each possible group in there devided by a |:
/^(.*( |\t))?TEST_?DIR( | := | = )/
In this case, at the beginning is no change to [ \t] because each group holds only one character and \t.
At the end, there must be (single space) or := (':=' surrounded by spaces) or = ('=' surrounded by spaces), following by anything...
You can use any combination...
/^(.*[ \t(])?TEST_?DIR([) =:]| :=| =|)/
Test it on Debuggex.com. (Use 'PCRE')

Avoiding duplicate items in a comma-separated list of two-letter words

I need to write a regex which allows a group of 2 chars only once. This is my current regex :
^([A-Z]{2},)*([A-Z]{2}){1}$
This allows me to validate something like this :
AL,RA,IS,GD
AL
AL,RA
The problem is that it validates also AL,AL and AL,RA,AL.
EDIT
Here there are more details.
What is allowed:
AL,RA,GD
AL
AL,RA
AL,IS,GD
What it shouldn't be allowed:
AL,RA,AL
AL,AL
AL,RA,RA
AL,IS,AL
IS,IS,AL
IS,GD,GD
IS,GD,IS
I need that every group of two characters appears only once in the sequence.
Try something like this expression:
/^(?:,?(\b\w{2}\b)(?!.*\1))+$/gm
I have no knowledge of swift, so take it with a grain of salt. The idea is basically to only match a whole line while making sure that no single matched group occurs at a later point in the line.
First of all, let's shorten your pattern. It can be easily achieved since the length of each comma-separated item is fixed and the list items are only made up of uppercase ASCII letters. So, your pattern can be written as ^(?:[A-Z]{2}(?:,\b)?)+$. See this regex demo.
Now, you need to add a negative lookahead that will check the string for any repeating two-letter sequence at any distance from the start of string, and within any distance between each. Use
^(?!.*\b([A-Z]{2})\b.*\b\1\b)(?:[A-Z]{2}(?:,\b)?)+$
See the regex demo
Possible implementation in Swift:
func isValidInput(Input:String) -> Bool {
return Input.range(of: #"^(?!.*\b([A-Z]{2})\b.*\b\1\b)(?:[A-Z]{2}(?:,\b)?)+$"#, options: .regularExpression) != nil
}
print(isValidInput(Input:"AL,RA,GD")) // true
print(isValidInput(Input:"AL,RA,AL")) // false
Details
^ - start of string
(?!.*\b([A-Z]{2})\b.*\b\1\b) - a negative lookahead that fails the match if, immediately to the right of the current location, there is:
.* - any 0+ chars other than line break chars, as many as possible
\b([A-Z]{2})\b - a two-letter word as a whole word
.* - any 0+ chars other than line break chars, as many as possible
\b\1\b - the same whole word as in Group 1. NOTE: The word boundaries here are not necessary in the current scenario where the word length is fixed, it is two, but if you do not know the word length, and you have [A-Z]+, you will need the word boundaries, or other boundaries depending on the situation
(?:[A-Z]{2}(?:,\b)?)+ - 1 or more sequences of:
[A-Z]{2} - two uppercase ASCII letters
(?:,\b)? - an optional sequence: , only if followed with a word char: letter, digit or _. This guarantees that , won't be allowed at the end of the string
$ - end of string.
You can use a negative lookahead with a back-reference:
^(?!.*([A-Z]{2}).*\1).*
if, as in the all the examples in the question, it is known that the string contains only comma-separated pairs of capital letters. I will relax that assumption later in my answer.
Demo
The regex performs the following operations:
^ # match beginning of line
(?! # begin negative lookahead
.* # match 0+ characters (1+ OK)
([A-Z]{2}) # match 2 uppercase letters in capture group 1
.* # match 0+ characters (1+ OK)
\1 # match the contents of capture group 1
) # end negative lookahead
.* # match 0+ characters (the entire string)
Suppose now that one or more capital letters may appear between each pair of commas, or before the first comma or after the last comma, but it is only strings of two letters that cannot be repeated. Moreover, I assume the regex must confirm the regex has the desired form. Then the following regex could be used:
^(?=[A-Z]+(?:,[A-Z]+)*$)(?!.*(?:^|,)([A-Z]{2}),(?:.*,)?\1(?:,|$)).*
Demo
The regex performs the following operations:
^ # match beginning of line
(?= # begin pos lookahead
[A-Z]+ # match 1+ uc letters
(?:,[A-Z]+) # match ',' then by 1+ uc letters in a non-cap grp
* # execute the non-cap grp 0+ times
$ # match the end of the line
) # end pos lookahead
(?! # begin neg lookahead
.* # match 0+ chars
(?:^|,) # match beginning of line or ','
([A-Z]{2}) # match 2 uc letters in cap grp 1
, # match ','
(?:.*,) # match 0+ chars, then ',' in non-cap group
? # optionally match non-cap grp
\1 # match the contents of cap grp 1
(?:,|$) # match ',' or end of line
) # end neg lookahead
.* # match 0+ chars (entire string)
If there is no need check that the string contains only comma-separated strings of one or more upper case letters the postive lookahead at the beginning can be removed.

Get Event Log Message content in a Variable

I want to get the the first "WDS.Device.ID" (00-15-5D-8A-44-25) (without the [] brackets) into a variable.
I tried some RegEx things but without success as I lack the knowledge for it.
PS C:\Windows\system32> $result | fl
Message : A device query was successfully processed (status 0x0):
Input:
WDS.Request.Type='Deployment'
WDS.Client.Property.Architecture.Process='X64'
WDS.Client.Property.Architecture.Native='X64'
WDS.Client.Property.Firmware.Type='BIOS'
WDS.Client.Property.SMBIOS.Manufacturer='Microsoft Corporation'
WDS.Client.Property.SMBIOS.Model='Virtual Machine'
WDS.Client.Property.SMBIOS.Vendor='American Megatrends Inc.'
WDS.Client.Property.SMBIOS.Version='090008 '
WDS.Client.Property.SMBIOS.ChassisType='Desktop'
WDS.Client.Property.SMBIOS.UUID={CCD695BE-20AB-48CC-8F01-319B498F7A69}
WDS.Client.Request.Version=1.0.0.0
WDS.Client.Version=10.0.18362.1
WDS.Client.Host.Version=10.0.18362.1
WDS.Client.DDP.Default.Match=FALSE
WDS.Device.ID=[00-15-5D-8A-44-25]
WDS.Device.ID=[BE-95-D6-CC-AB-20-CC-48-8F-01-31-9B-49-8F-7A-69]
Output:
WDS.Client.Property.Architecture.Process='X64'
WDS.Client.Property.Architecture.Native='X64'
WDS.Client.Property.Firmware.Type='BIOS'
WDS.Client.Property.SMBIOS.Manufacturer='Microsoft Corporation'
WDS.Client.Property.SMBIOS.Model='Virtual Machine'
WDS.Client.Property.SMBIOS.Vendor='American Megatrends Inc.'
WDS.Client.Property.SMBIOS.Version='090008 '
WDS.Client.Property.SMBIOS.ChassisType='Desktop'
WDS.Client.Property.SMBIOS.UUID={CCD695BE-20AB-48CC-8F01-319B498F7A69}
WDS.Client.Request.Version=1.0.0.0
WDS.Client.Version=10.0.18362.1
WDS.Client.Host.Version=10.0.18362.1
WDS.Client.DDP.Default.Match=FALSE
WDS.Client.Request.ResendAuthenticated=TRUE
Turning my comment into an answer.
If the message you show is inside a string variable (let's call it $message), then you can use regex to get the value for the WDS.Device.ID without the brackets like this:
$devideID = ([regex]'(?i)WDS\.Device\.ID=\[((?:[0-9a-f]{2}-){5}[0-9a-f]{2})\]').Match($message).Groups[1].Value
Result:
00-15-5D-8A-44-25
Regex details:
WDS Match the characters “WDS” literally
\. Match the character “.” literally
Device Match the characters “Device” literally
\. Match the character “.” literally
ID= Match the characters “ID=” literally
\[ Match the character “[” literally
( Match the regular expression below and capture its match into backreference number 1
(?: Match the regular expression below
[0-9a-f] Match a single character present in the list below
A character in the range between “0” and “9”
A character in the range between “a” and “f”
{2} Exactly 2 times
- Match the character “-” literally
){5} Exactly 5 times
[0-9a-f] Match a single character present in the list below
A character in the range between “0” and “9”
A character in the range between “a” and “f”
{2} Exactly 2 times
)
] Match the character “]” literally
The (?i) in the regex makes it case-insensitive
here's another way to go about it. this presumes the $Result variable holds one multiline string AND that the 1st [ & the 1st ] are "bracketing" your target data. [grin]
$Result.Split('[')[1].Split(']')[0]
output = 00-15-5D-8A-44-25

Swift Regex Search String Except \r\n and \t

I am attempting to match phone numbers that is 6 digits or more with the following regex in swift. Phone numbers can also possess paranthesis and + for country codes.
"[0-9\\s\\-\\+\\(\\)]{6,}".
However, the above implementation matches \r\n and \t as well. How can I write the regex such that it will not match any \r\n or \t.
I attempted the following but didn't work:
"[0-9\\s\\-\\+\\(\\)(^\\r\\n\\t)]{6,}"
"[0-9\\s\\-\\+\\(\\)(?: (\\r|\\n|\\r\\n|\\t)]{6,}"
Thanks.
I suggest using
let regex = "^(?:[ +()-]*[0-9]){6,}[ +()-]*$"
Or
let regex = "^(?:[ +()-]*[0-9]){6,}[ +()-]*\\z"
Details
^ - start of string
(?:[ +()-]*[0-9]){6,} - six or more repetitions of
[ +()-]* - zero or more spaces, +, (, ) or - chars
[0-9] - a digit
[ +()-]* - zero or more spaces, +, (, ) or - chars
$ - end of string (\z is the very end of string).
If the pattern is used inside NSPredicate with MATCHES you may omit the ^ and $/\z anchors.

Scala string pattern matching for mathematical symbols

I have the following code:
val z: String = tree.symbol.toString
z match {
case "method +" | "method -" | "method *" | "method ==" =>
println("no special op")
false
case "method /" | "method %" =>
println("we have the special div operation")
true
case _ =>
false
}
Is it possible to create a match for the primitive operations in Scala:
"method *".matches("(method) (+-*==)")
I know that the (+-*) signs are used as quantifiers. Is there a way to match them anyway?
Thanks from a avidly Scala scholar!
Sure.
val z: String = tree.symbol.toString
val noSpecialOp = "method (?:[-+*]|==)".r
val divOp = "method [/%]".r
z match {
case noSpecialOp() =>
println("no special op")
false
case divOp() =>
println("we have the special div operation")
true
case _ =>
false
}
Things to consider:
I choose to match against single characters using [abc] instead of (?:a|b|c).
Note that - has to be the first character when using [], or it will be interpreted as a range. Likewise, ^ cannot be the first character inside [], or it will be interpreted as negation.
I'm using (?:...) instead of (...) because I don't want to extract the contents. If I did want to extract the contents -- so I'd know what was the operator, for instance, then I'd use (...). However, I'd also have to change the matching to receive the extracted content, or it would fail the match.
It is important not to forget () on the matches -- like divOp(). If you forget them, a simple assignment is made (and Scala will complain about unreachable code).
And, as I said, if you are extracting something, then you need something inside those parenthesis. For instance, "method ([%/])".r would match divOp(op), but not divOp().
Much the same as in Java. To escape a character in a regular expression, you prefix the character with \. However, backslash is also the escape character in standard Java/Scala strings, so to pass it through to the regular expression processing you must again prefix it with a backslash. You end up with something like:
scala> "+".matches("\\+")
res1 : Boolean = true
As James Iry points out in the comment below, Scala also has support for 'raw strings', enclosed in three quotation marks: """Raw string in which I don't need to escape things like \!""" This allows you to avoid the second level of escaping, that imposed by Java/Scala strings. Note that you still need to escape any characters that are treated as special by the regular expression parser:
scala> "+".matches("""\+""")
res1 : Boolean = true
Escaping characters in Strings works like in Java.
If you have larger Strings which need a lot of escaping, consider Scala's """.
E. g. """String without needing to escape anything \n \d"""
If you put three """ around your regular expression you don't need to escape anything anymore.