Swift extract regex matches
Even if the matchesInString()
method takes a String
as the first argument,
it works internally with NSString
, and the range parameter must be given
using the NSString
length and not as the Swift string length. Otherwise it will
fail for "extended grapheme clusters" such as "flags".
As of Swift 4 (Xcode 9), the Swift standard
library provides functions to convert between Range<String.Index>
and NSRange
.
func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex)
let results = regex.matches(in: text,
range: NSRange(text.startIndex..., in: text))
return results.map {
String(text[Range($0.range, in: text)!])
}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
Example:
let string = "€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]
Note: The forced unwrap Range($0.range, in: text)!
is safe because
the NSRange
refers to a substring of the given string text
.
However, if you want to avoid it then use
return results.flatMap {
Range($0.range, in: text).map { String(text[$0]) }
}
instead.
(Older answer for Swift 3 and earlier:)
So you should convert the given Swift string to an NSString
and then extract the
ranges. The result will be converted to a Swift string array automatically.
(The code for Swift 1.2 can be found in the edit history.)
Swift 2 (Xcode 7.3.1) :
func matchesForRegexInText(regex: String, text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [])
let nsString = text as NSString
let results = regex.matchesInString(text,
options: [], range: NSMakeRange(0, nsString.length))
return results.map { nsString.substringWithRange($0.range)}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
Example:
let string = "€4€9"
let matches = matchesForRegexInText("[0-9]", text: string)
print(matches)
// ["4", "9"]
Swift 3 (Xcode 8)
func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex)
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
Example:
let string = "€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]
Regular expressions in swift
Separate the string by non alpha numeric characters except white spaces. Then trim the elements with white spaces.
extension String {
func words() -> [String] {
return self.components(separatedBy: CharacterSet.alphanumerics.inverted.subtracting(.whitespaces))
.filter({ !$0.isEmpty })
.map({ $0.trimmingCharacters(in: .whitespaces) })
}
}
let string1 = "(name,john,string for user name)"
let string2 = "(name, john,name of john)"
let string3 = "key = value // comment"
print(string1.words())//["name", "john", "string for user name"]
print(string2.words())//["name", "john", "name of john"]
print(string3.words())//["key", "value", "comment"]
Regular expression to find a number ends with special character in Swift
You can use
func isValidItem(_ item: String) -> Bool {
let pattern = #"^[0-9]+\$\z"#
return (item.range(of: pattern, options: .regularExpression) != nil)
}
let arr = ["Foo", "Foo1", "Foo$", "$Foo", "1Foo", "1$", "20$", "1$Foo", "12$$"]
print(arr.filter {isValidItem($0)})
// => ["1$", "20$"]
Here,
^
- matches start of a line[0-9]+
- one or more ASCII digits (note that Swift regex engine is ICU and\d
matches any Unicode digits in this flavor, so[0-9]
is safer if you need to only match digits from the0-9
range)\$
- a$
char\z
- the very end of string.
See the online regex demo ($
is used instead of \z
since the demo is run against a single multiline string, hence the use of the m
flag at regex101.com).
Using regex in Swift
You may use
return word.replacingOccurrences(of: "\\W+", with: "", options: .regularExpression)
Note the options: .regularExpression
argument that actually enables regex-based search in the .replacingOccurrences
method.
Your pattern is [^\w]
. It is a negated character class that matches any char but a word char. So, it is equal to \W
.
The /.../
are regex delimiters. In Swift regex, they are parsed as literal forward slashes, and thus your pattern did not work.
The g
is a "global" modifier that let's a regex engine match multiple occurrences, but it only works where it is supported (e.g. in JavaScript). Since regex delimiters are not supported in Swift regex, the regex engine knows how to behave through the .replacingOccurrences
method definition:
Returns a new string in which all occurrences of a target string in the receiver are replaced by another given string.
If you need to check ICU regex syntax, consider referring to ICU User Guide > Regular Expressions, it is the regex library used in Swift/Objective-C.
Regex not working in swift. Giving an error invalid regex
Curly braces are special characters which have to be escaped
\{[^}]*\}
, in a Swift literal string \\{[^}]*\\}
By the way don't use the literal initializer of NSRange
to get the length of the string, the highly recommended way is
static func matches(regex: String, text: String) -> Bool {
do {
let regex = try NSRegularExpression(pattern: regex, options: .caseInsensitive)
let match = regex.firstMatch(in: text, options: [],
range: NSRange(text.startIndex..., in: text)
return match != nil
} catch {
print("invalid regex: \(error.localizedDescription)")
return false
}
}
Using Unicodes in Swift Regular Expression
You can use
extension String {
var patternMatchesWithUnicode: Bool {
return self.range(of: #"[\u4E00-\u9FFF]"#, options: .regularExpression) != nil
}
}
These will also work:
return self.range(of: #"[\x{4E00}-\x{9FFF}]"#, options: .regularExpression) != nil
return self.range(of: #"[\U00004E00-\U00009FFF]"#, options: .regularExpression) != nil
Swift regex flavor is ICU, see the excerpt from the docs page:
\uhhhh
- Match the character with the hex valuehhhh
.\Uhhhhhhhh
- Match the character with the hex valuehhhhhhhh
. Exactly eight hex digits must be provided, even though the largest Unicode code point is\U0010ffff
.\x{hhhh}
- Match the character with hex valuehhhh
. From one to six hex digits may be supplied.\xhh
- Match the character with two digit hex valuehh
.
Use regular expression in Swift String.contains() func
You are quite close
if thisString.range(of: "[^a-zA-Z0-9-]", options: .regularExpression) != nil {
//reject
} else {
//accept
}
(Swift) How to find all strings that matches regex in string
You would need to manually find all occurrences in your string using a while condition similar to the one used in this post and get the string subsequences instead of its range:
func findSrcs(_ content: String) -> [Substring] {
let pattern = #"(?<=src=")[^"]+"#
var srcs: [Substring] = []
var startIndex = content.startIndex
while let range = content[startIndex...].range(of: pattern, options: .regularExpression) {
srcs.append(content[range])
startIndex = range.upperBound
}
return srcs
}
Playground testing:
let content = """
<span>whatever</span>
<img src="smiley.gif" alt="Smiley face">
<span>whatever</span>
<img src="stackoverflow.jpg" alt="Stack Overflow">
"""
print(findSrcs(content))
This will print
["smiley.gif", "stackoverflow.jpg"]
Replace matches using regex by modifying matched string in swift
You may use
var value: NSMutableString = "It is live now at Germany(DE) or (SOFE)"
let pattern = "(?<=\\G(?<!\\A)|\\()[A-Za-z](?=[A-Za-z]+\\))"
let regex = try? NSRegularExpression(pattern: pattern)
regex?.replaceMatches(in: value, options: .reportProgress, range: NSRange(location: 0,length: value.length), withTemplate: "$0 ")
print(value)
Or just
let val = "It is live now at Germany(DE) or (SOFE)"
let pattern = "(?<=\\G(?<!\\A)|\\()[A-Za-z](?=[A-Za-z]+\\))"
print( val.replacingOccurrences(of: pattern, with: "$0 ", options: .regularExpression, range: nil) )
Output: It is live now at Germany(D E) or (S O F E)
Pattern details
(?<=\\G(?<!\\A)|\\()
- a positive lookbehind that matches a location right after(
or at the end of the preceding successful match[A-Za-z]
- matches and consumes any ASCII letter(?=[A-Za-z]+\\))
- a positive lookahead that matches a location that is immediately followed with 1+ ASCII letters and then a)
char.
The $0
in the replacement inserts the whole match value back into the resulting string.
Check string matches exact format swift 5
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 Topics
How to Get Uitouch Location from Uigesturerecognizer
Unknown Class in Interface Builder
Core Location Not Working in iOS 8
Opening Word,Excel, and PDF Files Without Using Uiwebview on iOS
How to Disable User Interaction on Mkmapview
Exception with Insertobject:Atindex: on iOS6
Module 'Alamofire' Has No Member Named 'Request'
Uicontroleventeditingchanged Doesn't Get Fired When Using Settext of Uitextfield
Completely Disable Firebase/Analytics to Stop Console Spam on App Startup
How to Detect an iOS App Installed or Upgraded
Full Resolution Screenshots for iPhone 6 and 6+
Zip and Unzip a File Programmatically in iOS
Autorelease Pools and When Release Is Called Under iOS
Removing Object from Array in Swift 3
Uinavigationcontroller Interactivepopgesturerecognizer Working Abnormal in iOS7
iOS Swift Converting Calendar Component Int Month to Medium Style String Month