Regex in Swift

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 the 0-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 value hhhh.

\Uhhhhhhhh - Match the character with the hex value hhhhhhhh. Exactly eight hex digits must be provided, even though the largest Unicode code point is \U0010ffff.

\x{hhhh} - Match the character with hex value hhhh. From one to six hex digits may be supplied.

\xhh - Match the character with two digit hex value hh.

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



Leave a reply



Submit