Damodar
Damodar

Reputation: 707

Regular expressions in swift

I'm bit confused by NSRegularExpression in swift, can any one help me?

task:1 given ("name","john","name of john")
then I should get ["name","john","name of john"]. Here I should avoid the brackets.

task:2 given ("name"," john","name of john")
then I should get ["name","john","name of john"]. Here I should avoid the brackets and extra spaces and finally get array of strings.

task:3 given key = value // comment
then I should get ["key","value","comment"]. Here I should get only strings in the line by avoiding = and //
I have tried below code for task 1 but not passed.

let string = "(name,john,string for user name)"
let pattern = "(?:\\w.*)"

do {
    let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
    let matches = regex.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
    for match in matches {
        if let range = Range(match.range, in: string) {
            let name = string[range]
            print(name)
        }
    }
} catch {
    print("Regex was bad!")
}


Thanks in advance.

Upvotes: 5

Views: 9031

Answers (5)

Damodar
Damodar

Reputation: 707

Here I have done with after understanding all of above comments.

let text = """
Capturing and non-capturing groups are somewhat advanced topics. You’ll encounter examples of capturing and non-capturing groups later on in the tutorial
"""

extension String {
            func  rex (_ expr : String)->[String] {
                return try! NSRegularExpression(pattern: expr, options: [.caseInsensitive])
                .matches(in: self, options: [], range: NSRange(location: 0, length: self.count))
                    .map {
                        String(self[Range($0.range, in: self)!])
                }
            }
        }
let r = text.rex("(?:\\w+-\\w+)") // pass any rex

Upvotes: 1

Rob
Rob

Reputation: 437552

Let’s consider:

let string = "(name,José,name is José)"

I’d suggest a regex that looks for strings where:

  • It’s the substring either after the ( at the start of the full string or after a comma, i.e., look behind assertion of (?<=^\(|,);
  • It’s the substring that does not contain , within it, i.e., [^,]+?;
  • It’s the substring that is terminated by either a comma or ) at the end of the full string, i.e., look ahead assertion of (?=,|\)$), and
  • If you want to have it skip white space before and after the substrings, throw in the \s*+, too.

Thus:

let pattern = #"(?<=^\(|,)\s*+([^,]+?)\s*+(?=,|\)$)"#
let regex = try! NSRegularExpression(pattern: pattern)
regex.enumerateMatches(in: string, range: NSRange(string.startIndex..., in: string)) { match, _, _ in
    if let nsRange = match?.range(at: 1), let range = Range(nsRange, in: string) {
        let substring = String(string[range])
        // do something with `substring` here
    }
}

Note, I’m using the Swift 5 extended string delimiters (starting with #" and ending with "#) so that I don’t have to escape my backslashes within the string. If you’re using Swift 4 or earlier, you’ll want to escape those back slashes:

let pattern = "(?<=^\\(|,)\\s*+([^,]+?)\\s*+(?=,|\\)$)"

Upvotes: 0

OOPer
OOPer

Reputation: 47886

A single pattern, works for test:1...3, in Swift.

let string =
    //"(name,john,string for user name)" //test:1
    //#"("name","       john","name of john")"# //test:2
    "key = value // comment" //test:3

let pattern = #"(?:\w+)(?:\s+\w+)*"# //Swift 5+ only
//let pattern = "(?:\\w+)(?:\\s+\\w+)*"

do {
    let regex = try NSRegularExpression(pattern: pattern)
    let matches = regex.matches(in: string, range: NSRange(0..<string.utf16.count))
    let matchingWords = matches.map {
        String(string[Range($0.range, in: string)!])
    }
    print(matchingWords) //(test:3)->["key", "value", "comment"]
} catch {
    print("Regex was bad!")
}

Upvotes: 0

Emma
Emma

Reputation: 27723

RegEx in Swift

These posts might help you to explore regular expressions in swift:

Task 1 & 2

This expression might help you to match your desired outputs for both Task 1 and 2:

"(\s+)?([a-z\s]+?)(\s+)?"

enter image description here


Based on Rob's advice, you could much reduce the boundaries, such as the char list [a-z\s]. For example, here, we can also use:

"(\s+)?(.*?)(\s+)?"

or

"(\s+)?(.+?)(\s+)?"

to simply pass everything in between two " and/or space.

enter image description here

RegEx

If this wasn't your desired expression, you can modify/change your expressions in regex101.com.

RegEx Circuit

You can also visualize your expressions in jex.im:

enter image description here

JavaScript Demo

const regex = /"(\s+)?([a-z\s]+?)(\s+)?"/gm;
const str = `"name","john","name of john"
"name","       john","name of john"
"       name  ","       john","name of john     "
"       name  ","       john","       name of john     "`;
const subst = `\n$2`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);

console.log('Substitution result: ', result);

Task 3

This expression might help you to design an expression for the third task:

(.*?)([a-z\s]+)(.*?)

enter image description here

const regex = /(.*?)([a-z\s]+)(.*?)/gm;
const str = `key = value // comment
key = value with some text // comment`;
const subst = `$2,`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);

console.log('Substitution result: ', result);

Upvotes: 3

RajeshKumar R
RajeshKumar R

Reputation: 15758

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"]

Upvotes: 2

Related Questions