Swift regular expression format? - ios

I'm familiar with doing pcre regexes, however they don't seem to work in swift.
^([1-9]\d{0,2}(\,\d{3})*|([1-9]\d*))(\.\d{2})?$
to validate numbers like 1,000,000.00
However, putting this in my swift function, causes an error.
extension String {
func isValidNumber() -> Bool {
let regex = NSRegularExpression(pattern: "^([1-9]\d{0,2}(\,\d{3})*|([1-9]\d*))(\.\d{2})?$", options: .CaseInsensitive, error: nil)
return regex?.firstMatchInString(self, options: nil, range: NSMakeRange(0, countElements(self))) != nil
}
}
"Invalid escape sequence in litteral"
This is of course, because pcre uses the "\" character, which swift interprets as an escape (I believe?)
So since I can't just use the regexes I'm used to. How do I translate them to be compatible with Swift code?

Within double quotes, a single backslash would be readed as an escape sequence. You need to escape all the backslashes one more time in-order to consider it as a regex backslash character.
"^([1-9]\\d{0,2}(,\\d{3})*|([1-9]\\d*))(\\.\\d{2})?$"

Edit (June 2022)
From Swift 5.7, which you can use on Xcode 14.0 Beta 1 or later, you can use /.../ like this:
// Regex type
let regex = /^([1-9]\d{0,2}(\,\d{3})*|([1-9]\d*))(\.\d{2})?$/
Edit (Dec 2022): Since this internally creates Regex introduced in iOS 16 and macOS 13, the minimum deployment target must cover that OS version.
Advantages over #"..."#:
Your regex pattern is parsed at the compile-time, so you don't need to worry if your pattern is valid or not once your program is compiled
If your pattern is invalid, the compiler lets you know specifically which part is invalid as the compile error
Syntax highlighting is applied
So your code would look like this:
extension String {
func isValidNumber() -> Bool {
let regex = /^([1-9]\d{0,2}(\,\d{3})*|([1-9]\d*))(\.\d{2})?$/
.ignoresCase()
return (try? regex.firstMatch(in: self)) != nil
}
}
Original answer
Since Swift 5, you can use #"..."# like this, so that you don't need to add extra escape sequences for Swift:
#"^([1-9]\d{0,2}(\,\d{3})*|([1-9]\d*))(\.\d{2})?$"#

Related

Error to use a shorter spelling to unwrap a value

in Swift documentation at https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html, there are examples about usage of optionals and unwrapping them. When I try the examples on my Macbook, I got an error as; "Variable binding in a condition requires an initializer".
Defining the variables part in document:
let nickname: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickname ?? fullName)"
Explanation and example parts which throws the error written above:
You can use a shorter spelling to unwrap a value, using the same name for that unwrapped value.
if let nickname {
print("Hey, \(nickname)")
}
Why I cannot use if let nickname and if it throws error, why it is written in the documentation?
The shorthand syntax for optional unwrapping with if let, guard let and while let was introduced in swift 5.7. I believe u are using an older version of swift.
Check this to find out which version of swift u are using.
For more details read the section Language updates -> Quality of life improvements.

What is `self` in swift?

I found this code in one of the old projects:
guard let `self` = self else {
return .empty()
}
static let `default`: LayoutParameters = { ..some code.. }
I assume `` was used in older versions of the language. But I would like to know why it is used/was used. Also, I would like to know if there are any problems if do not change the code and "leave it as is" in the latest versions of Swift and Xcode. Does it work correctly? Should I replace this with
guard let self = self else ......
self is a keyword and normally you cannot use keywords and reserved words in places outside their context. However, that sometimes creates problems. For that reason there is a special syntax to make the keyword to be a normal identifier, e.g.:
enum MyEnum: String {
case `default`
}
(also see Swift variable name with ` (backtick))
Historically self was not allowed as as a constant name inside guard-let-else and therefore backticks were commonly (ab)used.
They are no longer needed since Swift 4.2.
The code will still work correctly since you can wrap any identifier in backticks and it will just be a normal identifier.
The Xcode IDE suggestion you using `` to help to use the same default key in Foundation SDK.
Example: default is a constant name in Foundation, if you want using default to create new variable name is default you need add ``.
But you using SwiftLint with default rules, Using a default contants name is a code smell.

"Expected expression in Swift key path" Error while Refactoring code with Extensions

I have been trying refactor code by thanking functions and adding them in a separate file extension of a ViewController
What I have in this extension is a function that adds gesture recognizers to some views that have references to functions that I have placed in other file extension of the same ViewController. On build I am getting this error "Expected expression in Swift key path"
What is causing this error?
I got this error when I accidentally left a backslash after a bracket in my object init:
init(for note: Note, atAnchor anchor: ARAnchor) {\
let billboardNode = note.type.basicNode
self.node = billboardNode
self.text = note.description ?? "[No Text]"
self.type = note.type
addText()
}
Removing the backslash fixed the error. Check out this answer by user eharo2 for details about why!
Maybe you have typo, for example:
\//
// MyClass.swift
// yyy
//
// Created by xxx on 4/25/19.
// Copyright © 2019 xxx. All rights reserved.
//
import Foundation
class MyClass {
}
In this Case I accidentally wrote '\' at start.
This error message is a straight forward error, where the parser is expecting a keyPath, given the usage of the backslash (assuming that this is the issue causing the problem, considering that the previous answer from #Edmund Holderbaum was accepted).
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 5.0).”
Key-Path Expression. A key-path expression refers to a property or
subscript of a type. You use key-path expressions in dynamic
programming tasks, such as key-value observing. They have the
following form:
\type name.path
There seems to be few places in the Swift grammar where a backslash is used, other than in string interpolation (interpolated-text-item) or in a escaping sequence (escape-sequence).
from Summary of the Grammar - Lexical Structure
“key-path-expression → \ type opt . key-path-components”
Take a look at this excellent post to learn more about keyPaths in Swift: https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift

How to escape regex string

I have the following regex string used for determining a valid email address (including special characters e.g. ö, ê, ī, etc):
^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$
It's tested on https://regex101.com as working regex. I then want to include this string in my code so I have to escape it. I therefore ended up with the following string:
^(([^<>()[\\]\\\\.,;:\\s#\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s#\\\"]+)*)|(\\\".+\\\"))#((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$
Now, when I run my code:
private static func regexMatch(regex: String, string: String) -> Bool {
let stringTest = NSPredicate(format:"SELF MATCHES %#", regex)
return stringTest.evaluateWithObject(string)
}
My app crashes with the following error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Can't do regex matching, reason: Can't open pattern U_REGEX_MISSING_CLOSE_BRACKET (string scött.hôdśōn#example.com, pattern ^(([^<>()[]\.,;:\s#\"]+(.[^<>()[]\.,;:\s#\"]+)*)|(\".+\"))#(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$, case 0, canon 0)'
My guess is I am somehow escaping the regex string incorrectly. Can somebody point me in the right direction?
The comments about actually improving your regex should probably be heeded. There were a few things you were not escaping when you should, specifically ] and escaping when you didnt need to, specifically . inside [] and ". After fixing these in your regex
^(([^<>()[\].,;:\s#"]+(.[^<>()[\].,;:\s#"]+)*)|(".+"))#(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$
And then escaping for special characters, we get
"/^(([^<>()[\\].,;:\\s#\"]+(.[^<>()[\\].,;:\\s#\"]+)*)|(\".+\"))#(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/"
I suspect the "missing bracket" error was caused by the improper escaping of ] which prematurely closed some alternator blocks you had. Again, the commentators on your post are correct that the regex itself could definitely be improved
I updated my regex string to the following and now it seems to be working.
^([^x00-\\\\x7F]|[\\w-\\.])+#((([^x00-\\\\x7F]|)[\\w-])+\\.)+[\\w-]{2,4}$

Nil-coalescing to provide default values in Swift 1.2

Previously (i.e. prior to Swift 1.2) I've used code like this:
self.name = jsonDictionary["name"] as? String ?? "default name string here"
I've found this to be a readable but concise way of:
getting a value from a dictionary
checking it's of the type I'm expecting
assigning a default value
However in Swift 1.2, I get this compiler error:
Consecutive statements on a line must be separated by ';'
I can't see anything in the Xcode 6.3 release notes or the Apple Swift Blog about this.
Seems you now have to use brackets:
self.name = (jsonDictionary["name"] as? String) ?? "default name string here"

Resources