Check string matches exact format swift 5 - swift

I want to check if a string matches an exact regex pattern;
Currently, even though the string being compared is not an exact match, my function is returning true.
Pattern String: "([0-9],[0-9])"
For example,
(1,1) is valid
(5,4) is valid
Only strings entered in this format are valid I.E. Bracket Number Comma Number Bracket (Without spaces)
I.E.
[5,5] is not valid
{5,5] is not valid.
5,5 is not valid
Code I am using to check:
let stringToCheck = "[5,5]"
return stringToCheck.range(of: "([0-9],[0-9])", options: .regularExpression, range: nil, locale: nil) != nil
Can anyone help me with how to adjust this to check for exact matches in line with my pattern?
Thanks!

You need two things:
Escape parentheses
Add anchors because in the current code, the regex can match a part of a string.
You can thus use
stringToCheck.range(of: #"^\([0-9],[0-9]\)\z"#, options: .regularExpression, range: nil, locale: nil) != nil
Note the # chars on both ends, they allow escaping with single backslashes.
Details:
^ - start of string
\( - a ( char
[0-9] - a single ASCII digit (add + after ] to match one or more digits)
, - a comma
[0-9] - a single ASCII digit (add + after ] to match one or more digits)
\) - a ) char
\z - the very end of string (if linebreaks cannot be present in the string, $ is enough).

Related

How can I individuate the text that encloses some other text in a pattern and edit it with regex

I'm learning about regex and I'm trying to create a program where a certain pattern is substituted.
Given the following string:
###hello#!
I want to recognise "###" and "#!" and substitute them with "*** and "*^". What's between these characters must remain as it is.
Now, I tried something like:
text.replacingOccurrences(of: #"(###)"#, with: "***", options: .regularExpression)
text.replacingOccurrences(of: #"(#!)"#, with: "*^", options: .regularExpression)
but if my string is:
"###hello#! ###hello###"
my output becomes:
"**hello^ hello"
while the desired one should be:
"**hello^ ###hello###"
In fact I only want the characters to be substituted when they follow the pattern:
### some text #!
I created a regex with the following pattern:
#"(###)(?:\\.*?)(#!)"#
but I'm not able to get the text and substitute it.
How can I individuate the text that encloses some other text in a pattern and edit it?
You can use
text = text.replacingOccurrences(of: #"(?s)###(.*?)#!"#, with: "***$1*^", options: .regularExpression)
See the regex demo. Details:
(?s) - an inline "singleline" flag that makes . match any char
### - left-hand delimiter
(.*?) - Capturing group 1 ($1 refers to this value): any zero or more chars as few as possible
#! - right-hand delimiter.
Swift test:
let text = "###hello#! ###hello###"
print(text.replacingOccurrences(of: #"(?s)###(.*?)#!"#, with: "***$1*^", options: .regularExpression))
// -> ***hello*^ ###hello###

Regular expression with backslash in swift

i am having problems using replacingOccurrences to replace a word after some specific keywords inside a textview in swift 5 and Xcode 12.
For example:
My textview will have the following string "NAME\JOHN PHONE\555444333"
"NAME" and "PHONE" will be unique so anytime i change the proper field i want to change the name or phone inside this textview.
let's for example change JOHN for CLOE with the code
txtOther.text = txtOther.text.replacingOccurrences(of: "NAME(.*?)\\s", with: "NAME\\\(new_value) ", options: .regularExpression)
print (string)
output: "NAMECLOE " instead of "NAME\CLOE "
I can't get the backslash to get print according to the regular expression.
Or maybe change the regex expression just to change JOHN for CLOE after "NAME"
Thanks!!!
Ariel
You can solve this by using a raw string for your regular expresion, that is a string surrounded with #
let pattern = #"(NAME\\)(.*)\s"#
Note that name and the \ is in a separate group that can be referenced when replacing
let output = string.replacingOccurrences(of: pattern, with: "$1\(new_value) ", options: .regularExpression)
Use
"NAME\\JOHN PHONE\\555444333".replacingOccurrences(
of: #"NAME\\(\S+)"#,
with: "NAME\\\\\(new_value)",
options: .regularExpression
)
Double backslashes in the replacement, backslash is a special metacharacter inside a replacement.
\S+ matches one or more characters different from whitespace, this is shorter and more efficient than .*?\s, and you do not have to worry about how to put back the whitespace.

Extracting range of unpadded string

I'd like to extract the Range<String.Index> of a sentence within its whitespace padding. For example,
let padded = " El águila (🦅). "
let sentenceRangeInPadded = ???
assert(padded[sentenceRangeInPadded] == "El águila (🦅).") // The test!
Here's some regex that I started with, but looks like variable length lookbehinds aren't supported.
let sentenceRangeInPadded = padded.range(of: #"(?<=^\s*).*?(?=\s*$)"#, options: .regularExpression)!
I'm not looking to extract the sentence (could just use trimmingCharacters(in:) for that), just the Range.
Thanks for reading!
You may use
#"(?s)\S(?:.*\S)?"#
See the regex demo.
Details
(?s) - a DOTALL modifier making . match any char, including line break chars
\S - the first non-whitespace char
(?:.*\S)? - an optional non-capturing group matching
.* - any 0+ chars as many as possible
\S - up to the last non-whitespace char.

Match all substrings in string except specific pattern

in this string: "TESTING (hello) 123 (HOW ARE YOU)"
I would like to match:
TESTING
123
Please help.. thanks!
I am only able to use (\\\(.*?\)) to match \(hello) and \(HOW ARE YOU), how can i match the counterpart of this strings?
There is no way with ICU (the regex library used in Swift) regex to match a text chunk that is not equal to some multicharacter string. You could do it if you wanted to match any 1 or more chars other than some specific character. You can't do it if you are "negating" a whole sequence of chars.
You may use
let str = "TESTING \\(hello) 123 \\(HOW ARE YOU)"
let pattern = "\\s*\\\\\\([^()]*\\)\\s*"
let result = str.replacingOccurrences(of: pattern, with: "\0", options: .regularExpression)
print(result.components(separatedBy: "\0").filter({ $0 != ""}))
Output: ["TESTING", "123"]
The idea is to match what you do not need and replace them with a null char, and then split the string with that null char.
Pattern details
\s* - 0+ whitespaces
\\\( - a \( substring
[^()]* - 0+ chars other than ( and )
\) - a ) char
\s* - 0+ whitespaces.
The results are likely to contain empty strings, hence .filter({ $0 != ""}) is used to filter them out.

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.