Swift Use of unresolved operator '=~' - swift

I'm trying to find a code for swift password strength checker, then I see this from github I fix some codes but there's a operator that I don't understand, it's =~
This is my code
enum PasswordStrength: Int {
case None
case Weak
case Moderate
case Strong
static func checkStrength(password: String) -> PasswordStrength {
var len: Int = password.count
var strength: Int = 0
switch len {
case 0:
return .None
case 1...4:
strength += 1
case 5...8:
strength += 2
default:
strength += 3
}
// Upper case, Lower case, Number & Symbols
let patterns = ["^(?=.*[A-Z]).*$", "^(?=.*[a-z]).*$", "^(?=.*[0-9]).*$", "^(?=.*[!##%&-_=:;\"'<>,`~\\*\\?\\+\\[\\]\\(\\)\\{\\}\\^\\$\\|\\\\\\.\\/]).*$"]
for pattern in patterns {
if (password =~ pattern).boolValue {
strength += 1
}
}
switch strength {
case 0:
return .None
case 1...3:
return .Weak
case 4...6:
return .Moderate
default:
return .Strong
}
}
}
and my error Use of unresolved operator '=~' was pointing at =~, what's the meaning of it and how can I resolve it?

=~ seems like a custom operator (or maybe the pattern matching operator ~= was different in previous Swift version, but I doubt that, since the pattern matching operator cannot handle regex matching or at least cannot handle it in Swift 5).
You can replace the =~ with if password.range(of: pattern, options: .regularExpression) != nil to check if a regular expression matches your password.
Also, enum cases should be lowerCamelCase
Full working code:
enum PasswordStrength: Int {
case none
case weak
case moderate
case strong
static func checkStrength(password: String) -> PasswordStrength {
let len = password.count
var strength: Int = 0
switch len {
case 0:
return .none
case 1...4:
strength += 1
case 5...8:
strength += 2
default:
strength += 3
}
// Upper case, Lower case, Number & Symbols
let patterns = ["^(?=.*[A-Z]).*$", "^(?=.*[a-z]).*$", "^(?=.*[0-9]).*$", "^(?=.*[!##%&-_=:;\"'<>,`~\\*\\?\\+\\[\\]\\(\\)\\{\\}\\^\\$\\|\\\\\\.\\/]).*$"]
for pattern in patterns {
if password.range(of: pattern, options: .regularExpression) != nil {
strength += 1
}
}
switch strength {
case 0:
return .none
case 1...3:
return .weak
case 4...6:
return .moderate
default:
return .strong
}
}
}
You can also simplify the for loop by using a where clause like this:
for pattern in patterns where password.range(of: pattern, options: .regularExpression) != nil {
strength += 1
}

Related

Is there a way in Swift to get an associated value without using a switch statement?

When I have a situation where I already know enum case statement I want to get the associated value of, is there a cleaner way than using a switch statement to pluck out the associated value?
To have to come up with a switch statement, provide multiple cases, or a default case just to extract the associated value is gaudy.
enum CircularReasoning {
case justPi(pi: Double)
case pizzaPie(howMany: Int)
}
var piInTheSky : Double
let whatLogic = CircularReasoning(pi: 3.1415926)
⬇️ 𝘸𝘒𝘯𝘡 𝘡𝘰 𝘒𝘷𝘰π˜ͺπ˜₯ ⬇️
switch whatLogic {
case .justPi(let pi):
piInTheSky = pi!
default:
break
}
You can use if case .<enum_case>(let value) as in TylerP's example,
or if case let .<enum_case>(value):
enum Foo {
case anInt(Int)
case aFloat(Float)
}
let aFoo: Foo = .anInt(9)
// Example of `if case .<enum_case)(let value)` syntax:
if case .anInt(let aValue) = aFoo {
print("aFoo = anInt(\(aValue))")
// Example of `if case let .enum_case(value)` syntax:
} else if case let .aFloat(aValue) = aFoo {
print("aFoo = aFloat(\(aValue))")
}
Both work. I'm not sure why the language includes both variants.
If you only care about one enum type, then either if syntax makes sense to me. If you are dealing with more than one possible enum value then the switch version seems cleaner.
Here's an adaptation of #DuncanC's excellent upvoted and accepted answer, as applied to a fictitious version of my real-world use case.
It illustrates a possible way to use his answer to reduce the space required to extract associated values, especially if one has a lot of one-off cases...
Note: Not implying this is appropriate or professional swift styling; it's clearly idiosyncratic, yet compact. (I usually don't compress things into one liners like this, unless they get really repetitive/redundant & produce lot of pointless vertical bloat).
enum RealmKey { case realmOfRealms, anyOldRealm, someOtherRealm }
.
.
.
enum SymbolToken {
case realm (key: RealmKey?)
case space (key: SpaceKey?)
case area (key: AreaKey?)
case region (key: RegionKey?)
case preserve (key: PeserveKey?)
case openParen
case closeParen
case logicalAnd
case logicalOr
case logicalNot
var realmKey : RealmKey? { if case .realm (let key) = self { return key } else { return nil } }
var spaceKey : SpaceKey? { if case .space (let key) = self { return key } else { return nil } }
var areaKey : AreaKey? { if case .area (let key) = self { return key } else { return nil } }
var regionKey : RegionKey? { if case .region (let key) = self { return key } else { return nil } }
var preserveKey : PreserveKey? { if case .preserve (let key) = self { return key } else { return nil } }
}
let realm = SymbolToken.realm(.realmOfRealms)
let realmKey = realm.realmKey

Swift 3 enum with associated value AND function comparison

I have this struct that has an enum property as well as a function:
struct UserInput {
enum State {
case unrestricted
case restricted(because: WarningType)
enum WarningType {
case offline
case forbidden
}
}
var config: UserInputConfig?
var state: State = .unrestricted
func isConfigured() -> Bool {
// Arbitrary checks about the config...
}
}
Is there a way to rewrite the following conditionals so that the check for isConfigured() and state are in the same statement?
if case .restricted = userInput.state {
return 1
} else if userInput.isConfigured() {
return 1
} else {
return 0
}
It seems because the State enum uses associated values, you cannot simply write if userInput.state == .restricted || userInput.isConfigured(), you need to use the if case syntax. There must be a way around this?
You would like to do this:
if case .restricted = userInput.state || userInput.isConfigured() {
return 1
} else {
return 0
}
but there is currently no way to do an OR with pattern matching. There are a couple of ways of doing AND.
By using DeMorgan's Laws, you can turn if a || b into if !(!a && !b) and by reversing the then and else clauses of your if statement, you can just check for if !a && !b.
Unfortunately, you can't say if !(case .restricted = userInput.state), but since your enum has only 2 cases, you can replace that with if case .unrestricted = userInput.state.
Now, how do you use that with another statement? You can't use && for the same reason you can't use ||.
You can check for the failing case by using a pattern that matches both failing conditions (which is using AND) and then return 1 if both failing conditions aren't met:
if case (.unrestricted, false) = (userInput.state, userInput.isConfigured()) {
return 0
} else {
return 1
}
Equivalently you can use a multi-clause condition:
if case .unrestricted = userInput.state, !userInput.isConfigured() {
return 0
} else {
return 1
}
In addition to being shorter and IMO easier to read, this second method can short circuit and skip calling userInput.isConfigured in the case where case .unrestricted = userInput.state fails.
You can do it really cleanly with a switch statement, and pattern matching:
switch userInput.state
{
case .unrestricted:
return userInput.isConfigured() ? 1 : 0;
case .restricted(_):
return 1
}

finding a number in a range swift 3

I have a number that I get from JSON, this number represents an age. Users give me a range of two ages and may code is supposed to check if this number I'm getting from JSON is in the range.
here is my code and it gives me error
Type of Expression is ambiguous without more context?
let age = "40"
if Int(AgeFrom) ... Int(AgeTO) ~= Int(age) {
print("yes")
}
Update
if let value: AnyObject = response.result.value as AnyObject? {
var ages = String
let json = JSON(value)
for (key, subJson) in json {
ages.append(subJson["age"].string!)
}
guard let min = Int(self.DropDownFrom.selectedItem!) else { return }
guard let max = Int(self.DropDownTo.selectedItem!) else { return }
for fitage in ages {
switch ages
{
case (min...max):
print ("Age is in range")
default:
print ("Nope, not this time")
}
}
Still gives me an error.
You need to unwrap the optionals because the Int(:String) method might not have a valid answer.
Best way to do this is kind of thing is with guard
guard let min = Int(AgeFrom) else { return }
guard let max = Int(AgeTo) else { return }
And from there you can go with the simple if statement:
if (min <= age && age <= max)
{
print ("Age is in range")
}
or get really fancy and use the switch statement pattern matching syntax (which I much prefer)
switch age
{
case (min...max):
print ("Age is in range")
default:
print ("Nope, not this time")
}
if - simplicity and readability
It is a basic thing in programming, checking if an optional is between two other optional values with an if:
if Int(AgeFrom)! <= Int(age)! && Int(AgeTO)! >= Int(age)! {
print("It is in the range!")
}
switch - multiple cases handling
However, I recommend using a switch for case handling:
switch(Int(AgeFrom)! <= Int(age)!, Int(AgeTO)! >= Int(age)!){
case (true,true): print("Yes, it fits the range")
case (false,true): print("Too young!")
case (true,false): print("Too old!")
}
The second solution is far better for multiple cases of the age value, especially when it's outside the range.
Hope it helps!
You can also use optional binding:
if let ageFrom = Int(ageFrom),
let ageTo = Int(ageTo),
ageFrom...ageTo ~= age
{
print("yes")
} else {
print("no")
}
You have to unwrap the optionals:
if Int(AgeFrom)!...Int(AgeTO)! ~= Int(age)! {
print("yes")
}
of course that is the unsafe way of unwrapping, since it will crash if the conversion of AgeFrom, AgeTO or age fail.

Idiomatic way to model opcodes with embedded data in Swift

Swift enums seem like a great fit for modeling byte opcodes in Swift3. For example:
enum MathOpCode:UInt8 {
case Add = 0
case Subtract = 1
case Multiply = 2
case Divide = 3
}
let a = 42
let b = 13
let someByte = 2
if let opcode = OpCode(rawValue: someByte) {
switch opcode {
case .Add:
return a + b
case .Subtract:
return a - b
case .Multiply:
return a * b
case .Divide:
return a / b
}
}
This can be really expressive for writing binary protocols. The enum nicely captures the logical opcodes, and the switches read nicely then. Where it's breaking down for me, is where OpCodes include small amounts of data. IOW, let's say I add an OpCode called AddSmallConstant which is meant to represent all opcodes matching 0b01nnnnnn where the top two bits must be 01, but the bottom 6 bits are an embedded constant ranging 0-63. I could add 64 cases to my enum...
enum MathOpCode:UInt8 {
...
case AddConstant0 = 0b01000000
case AddConstant1 = 0b01000001
...
case AddConstant63 = 0b01111111
}
This doesn't really scale well. And to get the embedded value, I have to use rawValue and masking operations to get it anyway. And I can't have a switch statement that looks like
case MathOpCode.AddConstant0...MathOpCode.AddConstant63
to match the whole range, because enum cases can't be turned into ranges. The alternate is to use rawValue all over the place:
switch opCode.rawValue {
case MathOpCode.Add.rawValue:
...
case MathOpCode.Subtract.rawValue:
...
case (MathOpCode.AddConstant0.rawValue)...(MathOpCode.AddConstant63.rawValue):
...
}
Now the enum just seems like baggage, better to just define a bunch of constant let's up top of my my file. Am I missing a better pattern I can use in Swift to express these types of relationships and patterns?
As you know, Swift has a fancy feature called associated value for enum, but unfortunately, you cannot control raw bit representation of enum with associated value.
If you want to control raw bit representation of your MathOpCode type, you may need to create a RawRepresentable type.
For example, you can write something like this:
struct MathOpCode: RawRepresentable {
var rawValue: UInt8
init(rawValue: UInt8) {self.rawValue = rawValue}
static let add = MathOpCode(rawValue: 0)
static let subtract = MathOpCode(rawValue: 1)
static let multiply = MathOpCode(rawValue: 2)
static let divide = MathOpCode(rawValue: 3)
static let addConstant = MathOpCode(rawValue: 0b0100_0000)
static func add(constant value: UInt8) -> MathOpCode {
guard value < 64 else {fatalError("constant out of bounds")}
return MathOpCode(rawValue: self.addConstant.rawValue + value)
}
var isAddConstant: Bool {return self.rawValue & 0b1100_0000 == MathOpCode.addConstant.rawValue}
var constant: UInt8 {return self.rawValue & 0b0011_1111}
}
//Prepare `matches` operator for `switch`.
func ~= (lhs: MathOpCode, rhs: MathOpCode) -> Bool {
return lhs == MathOpCode.addConstant && rhs.isAddConstant
|| lhs == rhs
}
You can use it as:
let opCode = MathOpCode.add(constant: 22)
switch opCode {
case MathOpCode.add:
print("add")
case MathOpCode.subtract:
print("subtract")
case MathOpCode.multiply:
print("multiply")
case MathOpCode.divide:
print("divide")
case MathOpCode.addConstant:
print("addConstant", opCode.constant)
default:
print("invalid opCode")
}
//->addConstant 22

How to compare enum with associated values by ignoring its associated value in Swift?

After reading How to test equality of Swift enums with associated values, I implemented the following enum:
enum CardRank {
case Number(Int)
case Jack
case Queen
case King
case Ace
}
func ==(a: CardRank, b: CardRank) -> Bool {
switch (a, b) {
case (.Number(let a), .Number(let b)) where a == b: return true
case (.Jack, .Jack): return true
case (.Queen, .Queen): return true
case (.King, .King): return true
case (.Ace, .Ace): return true
default: return false
}
}
The following code works:
let card: CardRank = CardRank.Jack
if card == CardRank.Jack {
print("You played a jack!")
} else if card == CardRank.Number(2) {
print("A two cannot be played at this time.")
}
However, this doesn't compile:
let number = CardRank.Number(5)
if number == CardRank.Number {
print("You must play a face card!")
}
... and it gives the following error message:
Binary operator '==' cannot be applied to operands of type 'CardRank' and '(Int) -> CardRank'
I'm assuming this is because it's expecting a full type and CardRank.Number does not specify an entire type, whereas CardRank.Number(2) did. However, in this case, I want it to match any number; not just a specific one.
Obviously I can use a switch statement, but the whole point of implementing the == operator was to avoid this verbose solution:
switch number {
case .Number:
print("You must play a face card!")
default:
break
}
Is there any way to compare an enum with associated values while ignoring its associated value?
Note: I realize that I could change the case in the == method to case (.Number, .Number): return true, but, although it would return true correctly, my comparison would still look like its being compared to a specific number (number == CardRank.Number(2); where 2 is a dummy value) rather than any number (number == CardRank.Number).
Edit: As Etan points out, you can omit the (_) wildcard match to use this more cleanly:
let number = CardRank.Number(5)
if case .Number = number {
// Is a number
} else {
// Something else
}
Unfortunately, I don't believe that there's an easier way than your switch approach in Swift 1.2.
In Swift 2, however, you can use the new if-case pattern match:
let number = CardRank.Number(5)
if case .Number(_) = number {
// Is a number
} else {
// Something else
}
If you're looking to avoid verbosity, you might consider adding an isNumber computed property to your enum that implements your switch statement.
Unfortunately in Swift 1.x there isn't another way so you have to use switch which isn't as elegant as Swift 2's version where you can use if case:
if case .Number = number {
//ignore the value
}
if case .Number(let x) = number {
//without ignoring
}
In Swift 4.2 Equatable will be synthesized if all your associated values conform to Equatable. All you need to do is add Equatable.
enum CardRank: Equatable {
case Number(Int)
case Jack
case Queen
case King
case Ace
}
https://developer.apple.com/documentation/swift/equatable?changes=_3
What I usually do to compare if two enum cases "match" no matter their associated value is:
I have a protocol Matchable:
protocol Matchable {
static func ~= (lhs: Self, rhs: Self) -> Bool
}
Then I make enums conform to it:
extension CardRank: Matchable {
static func ~= (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case
(.number, .number),
(.jack, .jack),
(.queen, .queen),
(.king, .king),
(.ace, .ace):
return true
default:
return false
}
}
}
let card1: CardRank = .number(1)
let card2: CardRank = .number(2)
let card3: CardRank = .jack
print(card1 ~= card2) // true
print(card1 ~= card3) // false
Here's a simpler approach:
enum CardRank {
case Two
case Three
case Four
case Five
case Six
case Seven
case Eight
case Nine
case Ten
case Jack
case Queen
case King
case Ace
var isFaceCard: Bool {
return (self == Jack) || (self == Queen) || (self == King)
}
}
There's no need to overload the == operator, and checking for card type does not require confusing syntax:
let card = CardRank.Jack
if card == CardRank.Jack {
print("You played a jack")
} else if !card.isFaceCard {
print("You must play a face card!")
}
I didn't want to conform Equatable (it didn't help me either) and I wanted to filter for other cases than a specific one, so instead of simply writing card != .Number I had to write the following. (I adjusted my code to this question.)
enum CardRank {
...
var isNumber: Bool {
if case .Number = self { return true }
return false
}
}
So I can write not a number in a complex condition:
if something && !card.isNumber { ... }
I wish I could just write card != .Number, but the compiler was always complaining with Type of expression is ambiguous without more context. Maybe in an upcoming swift version!
You don't need func == or Equatable. Just use an enumeration case pattern.
let rank = CardRank.Ace
if case .Ace = rank { print("Snoopy") }
extension CardRank {
func isSameCaseAs(_ other: CardRank) -> Bool {
switch (self, other) {
case (.Number, .Number),
(.Jack, .Jack),
(.Queen, .Queen),
(.King, .King),
(.Ace, .Ace):
return true
default:
return false
}
}
}
let number = CardRank.Number(1)
let otherNumber = CardRank.Number(2)
number.isSameCaseAs(otherNumber) // true
Just create an extension and ignore the associated types.
From Swift 5.3, you can use the Comparable Enums feature:
enum CardRank: Comparable {
case Number(Int)
case Jack
case Queen
case King
case Ace
}
let cards: [CardRank] = [
.Queen, .Number(8), .Ace, .Number(3), .King
]
print(cards.sorted())
// [.Number(3), .Number(8), .Queen, .King, .Ace]