ashokds
ashokds

Reputation: 2288

How to add Ungreedy Search Flag Modifier in a Swift 5.2 based RegEx

How to use the Ungreedy flag in Swift 5.2 based RegEx?

Using Regex101.com to test it -

Link: https://regex101.com/r/mAvptf/1

It works when I have U flag assigned. Without U flag, it returns a single chunk of result back.

How do I use (?U) or .*? to have same effect as U flag?

// WARNING: You included a flag that Swift doesn't support: U
//          When this flag is set, it inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by '?'.
//          As an alternative, this effect can also be achieved by setting a (?U) modifier setting within the pattern or by a question mark behind a quantifier (e.g. .*?).

Playground code:

import Foundation

// WARNING: You included a flag that Swift doesn't support: U
//          When this flag is set, it inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by '?'.
//          As an alternative, this effect can also be achieved by setting a (?U) modifier setting within the pattern or by a question mark behind a quantifier (e.g. .*?).

let pattern = #"(- examples: \[\{(.*[\n])*).*?(?:\}\}\]$)"#
let regex = try! NSRegularExpression(pattern: pattern, options: .anchorsMatchLines)
let testString = #"""
    /**
     Gets a list of custom fields.
     - GET
     - OAuth:
       - name:
     - examples: [{contentType=application/json, example={
  "s" : [ {
    "name" : "name",
  }, {
    "name" : "name",
  } ],
  "fields" : [ {
    "items" : [ "listItems", "listItems" ],
    "name" : "name",
      "message" : "message"
    },
  }, {
    "items" : [ "listItems", "listItems" ],
    "name" : "name",
  } ]
}}]
     - returns: Request<Fields>
     */

    /**
     Gets a
     - examples: [{contentType=application/json, example={
  "fields" : [ {
    "name" : "name",
  } ],
  "fields" : [ {
    "listItems" : [ "listItems", "listItems" ],
    "name" : "name",
  } ]
}}]
     - returns: Request<fields>
     */
"""#
let stringRange = NSRange(location: 0, length: testString.utf16.count)
let matches = regex.matches(in: testString, range: stringRange)
var result: [[String]] = []
for match in matches {
    var groups: [String] = []
    for rangeIndex in 1 ..< match.numberOfRanges {
        let nsRange = match.range(at: rangeIndex)
        guard !NSEqualRanges(nsRange, NSMakeRange(NSNotFound, 0)) else { continue }
        let string = (testString as NSString).substring(with: nsRange)
        groups.append(string)
    }
    if !groups.isEmpty {
        result.append(groups)
    }
}
print(result)

I'm trying to get 2 separate results: Ungreedy works great, but it's not supported with Swift5.2

Expected Result

- examples: [{contentType=application/json, example={
  "s" : [ {
    "name" : "name",
  }, {
    "name" : "name",
  } ],
  "fields" : [ {
    "items" : [ "listItems", "listItems" ],
    "name" : "name",
      "message" : "message"
    },
  }, {
    "items" : [ "listItems", "listItems" ],
    "name" : "name",
  } ]
}}]

Upvotes: 0

Views: 221

Answers (1)

Andrew
Andrew

Reputation: 28539

To get the effect that you are wanting you can change your regular expression to the following.

let pattern = #"(- examples: \[\{(.*?[\n])*?).*?(?:\}\}\]$)"#

Note, after the first and second * I have added a ?. This gives the expression the same effect as the U flag.

You should now have access to both of the results, using your code above with the new expression gives the following output:

[
    [
        "- examples: [{contentType=application/json, example={\n  \"s\" : [ {\n    \"name\" : \"name\",\n  }, {\n    \"name\" : \"name\",\n  } ],\n  \"fields\" : [ {\n    \"items\" : [ \"listItems\", \"listItems\" ],\n    \"name\" : \"name\",\n      \"message\" : \"message\"\n    },\n  }, {\n    \"items\" : [ \"listItems\", \"listItems\" ],\n    \"name\" : \"name\",\n  } ]\n",
        "  } ]\n"
    ],
    [
        "- examples: [{contentType=application/json, example={\n  \"fields\" : [ {\n    \"name\" : \"name\",\n  } ],\n  \"fields\" : [ {\n    \"listItems\" : [ \"listItems\", \"listItems\" ],\n    \"name\" : \"name\",\n  } ]\n",
        "  } ]\n"
    ]
]

Here is it on https://regex101.com/r/FsJ5gZ/1


You may even be able to get rid of the first ? that I added and just use the following expression:

let pattern = #"(- examples: \[\{(.*[\n])*?).*?(?:\}\}\]$)"#

That seems enough to get your two results.

https://regex101.com/r/vPGRwk/1

Upvotes: 0

Related Questions