UnicodeScalar string has no value property in swift 3.0 - iphone

In swift 2.0 i had written below function that was working fine.
private func escape(string: String) -> String {
let unicode = string.unicodeScalars
var newString = ""
for i in unicode.startIndex ..< unicode.endIndex {
let char = unicode[i]
if char.value < 9 || (char.value > 9 && char.value < 32) // < 32 == special characters in ASCII, 9 == horizontal tab in ASCII
|| char.value == 39 { // 39 == ' in ASCII
let escaped = char.escape(asASCII: true)
newString.appendContentsOf(escaped)
} else {
newString.append(char)
}
}
return newString
}
But after update to Xcode 8 and Swift 3.0 my code has error that unicodeScalars has no property .value to access unicode value of a character. So what is the new property for the same in Swift3.0?

Something like this may be?
private func escape(string : String) -> String {
var newString = ""
string.unicodeScalars.forEach { char in
let expression = (char.value > 9 && char.value < 32)
(char.value < 9) || expression || (char.value == 39) ? newString.append(char.escaped(asASCII: true)) : newString.append(String(char))
}
return newString
}

Related

Convert Char in Int swift

I'm trying to convert a char in int, in C it works, but in Swift I've got some problem. It's not the same in C, using ascii I've got no problem.
This func is a piece of my atoi func.
I tried with binaryInt and UnicodeScalar, but didn't get success
func scanNumber(_ strArray: [Character], _ index: Int, _ flag: Int) -> Int {
var resalt = 0
while ((strArray[index] >= "0") && (strArray[index] <= "9")) {
// flag mean plus or minus sign in strArray, if flag = 2 it's like a ["-", "1", "2", "3"]
if flag != 2 {
resalt *= 10
resalt = resalt + Int(strArray[index]) //error
} else {
resalt *= 10
resalt = resalt - Int(strArray[index]) //error
}
}
return resalt
}
Int(strArray[index]) return:
Initializer 'init(_:)' requires that 'Character' conform to 'BinaryInteger'
Here is a solution using asciiValue
func scanNumber(_ strArray: [Character], _ index: Int, _ flag: Int) -> Int {
var resalt = 0
var arrayIndex = index
while (arrayIndex < strArray.count && (strArray[arrayIndex] >= "0") && (strArray[arrayIndex] <= "9")) {
guard let ascii = strArray[arrayIndex].asciiValue else {
return resalt
}
resalt *= 10
if flag != 2 {
resalt += Int(ascii) - 48
} else {
resalt -= Int(ascii) - 48
}
arrayIndex += 1
}
return resalt
}
I also fixed the loop
With a Character you can create a String. And with a String you can create an Int.
let char: Character = "1"
if let number = Int(String(char)) {
// use number
}

Wildcard Pattern Matching:

Wildcard Pattern Matching: Given a string and a pattern containing wildcard characters i.e. * and ?, where ? can match to any single character in the input string and * can match to any number of characters including zero characters, design an efficient algorithm to find if the pattern matches with the complete input string or not.
For example:
Input: string = "xyxzzxy", pattern = "x***y"
Output: Match
Input: string = "xyxzzxy", pattern = "x***x"
Output: No Match
Input: String = "xyxzzxy", pattern = "x***x?"
Output: Match
Input: String = "xyxzzxy", pattern = "*"
Output: Match
With the help of Foundation classes (in particular NSPredicate) you can implement wildcard matching simply as
func wildcard(_ string: String, pattern: String) -> Bool {
let pred = NSPredicate(format: "self LIKE %#", pattern)
return !NSArray(object: string).filtered(using: pred).isEmpty
}
The LIKE comparison does exactly what you want:
The left hand expression equals the right-hand expression: ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters.
Examples:
print(wildcard("xyxzzxy", pattern: "x***y")) // true
print(wildcard("xyxzzxy", pattern: "x***x")) // false
print(wildcard("xyxzzxy", pattern: "x***x?")) // true
print(wildcard("xyxzzxy", pattern: "*")) // true
print(wildcard("a12b34c", pattern: "a?b?c")) // false
print(wildcard("a12b34c", pattern: "a*b*c")) // true
If the question is to "design an efficient algorithm...", you could define an extension on String this way:
extension String {
func matches(wildcard pattern: String) -> Bool {
var strIndex = self.startIndex, matchIndex = self.startIndex
var patternIndex = pattern.startIndex, asteriskIndex = pattern.endIndex
while strIndex < self.endIndex {
//Characters match, or question mark
if patternIndex < pattern.endIndex
&& (self[strIndex] == pattern[patternIndex] || pattern[patternIndex] == "?") {
strIndex = self.index(after: strIndex)
patternIndex = pattern.index(after: patternIndex)
}
//Asterisk character
else if patternIndex < pattern.endIndex && pattern[patternIndex] == "*" {
asteriskIndex = patternIndex
matchIndex = strIndex
patternIndex = pattern.index(after: patternIndex)
}
else if asteriskIndex != pattern.endIndex {
patternIndex = pattern.index(after: asteriskIndex)
matchIndex = self.index(after: matchIndex)
strIndex = matchIndex
}
else { return false }
}
//Asterisk character at the end of the pattern
while patternIndex < pattern.endIndex && pattern[patternIndex] == "*" {
patternIndex = pattern.index(after: patternIndex)
}
return patternIndex == pattern.endIndex
}
}
It is a more readable version of this code.
Here are some test cases:
"xyxzzxy".matches(wildcard: "x***y") //true
"xyxzzxy".matches(wildcard: "x***x") //false
"xyxzzxy".matches(wildcard: "x***x?") //true
"xyxzzxy".matches(wildcard: "*") //true
Taking Martin's solution a step further, here's a [String] extension that will accept a pattern and return all matching elements:
extension Array where Element == String {
func wildcard(pattern: String) -> [String] {
var returnArray: [String] = []
for item in self {
if (wildcard(item, pattern: pattern)) {
returnArray.append(item)
}
}
return returnArray
}
// Credit to Martin R # SO for this brilliance: https://stackoverflow.com/a/57271935/215950
private func wildcard(_ string: String, pattern: String) -> Bool {
let pred = NSPredicate(format: "self LIKE %#", pattern)
return !NSArray(object: string).filtered(using: pred).isEmpty
}
}
func matchingString() {
var savingValueOfJ = 0
var boolean = [Bool]()
inputString = inputStringTextField.text!
pattern = patternTextField.text!
let inputCharacters = Array(inputString)
let patternCharacters = Array(pattern)
for (index, firstCharacter) in patternCharacters.enumerated() {
if index == patternCharacters.count - 1, index != 0 {
if inputCharacters.last == firstCharacter || firstCharacter == "*" || firstCharacter == "?" {
boolean.append(true)
break
}
else {
boolean.append(false)
break
}
} else {
if firstCharacter != "*" {
while savingValueOfJ <= inputCharacters.count {
if firstCharacter == inputCharacters[savingValueOfJ] || firstCharacter == "?" {
boolean.append(true)
savingValueOfJ += 1
break
} else {
boolean.append(false)
savingValueOfJ += 1
break
}
}
}
}
}
let arr = boolean.filter{ $0 == false}
if arr.count > 0 {
displayingResultLbl.text = "Not A Match"
}
else {
displayingResultLbl.text = "Matche's"
}
}

Need to find consecutive sequence like "6789" or "abcd" in Swift

I need help to find consecutive sequence for example more than 3 characters in ascending order. I've already implemented one solution but It's not universal.
Examples what should be found - "1234", "abcd", "5678".
And what shouldn't be found - "123", "adced", "123abc", "89:;"
Particularly the case "89:;", symbol ":" - is 58 in uniCode and "9" - is 57, that's why my approach does not work in the case.
Implementation should be in swift.
Additional clarification
For now it would be enough to find the sequences only in English letters and numbers.
private func findSequence(sequenceLength: Int, in string: String) -> Bool {
let scalars = string.unicodeScalars
var unicodeArray: [Int] = scalars.map({ Int($0.value) })
var currentLength: Int = 1
var i = 0
for number in unicodeArray {
if i+1 >= unicodeArray.count {
break
}
let nextNumber = unicodeArray[i+1]
if number+1 == nextNumber {
currentLength += 1
} else {
currentLength = 1
}
if currentLength >= sequenceLength {
return true
}
i += 1
}
return false
}
var data = [1,2,5,4,56,6,7,9,6,5,4,5,1,2,5,4,56,6,7,9,8,1,1,2,5,4,56,6,7,9,8,1,1,2,5,4,56,6,7,9,8,1,1,2,5,4,56,6,7,9,8,1,1,2,5,4,56,6,7,9,8,11,2,5,4,56,6,7,9,8,1,2,3]
for i in 0...data.count{
if i+2 < data.count{
if Int(data[i] + data[i+2]) / 2 == data[i+1] && Int(data[i] + data[i+2]) % data[i+1] == 0 && data[i+1] != 1 && data[i] < data[i+1]{
print(data[i] ,data[i+1], data[i+2])
}
}
}
You can check for sequence with CharacterSet
func findSequence(sequenceLength: Int, in string: String) -> Bool {
// It would be better to extract this out of func
let digits = CharacterSet.decimalDigits
let lowercase = CharacterSet(charactersIn: "a"..."z")
let uppercase = CharacterSet(charactersIn: "A"..."Z")
let controlSet = digits.union(lowercase).union(uppercase)
// ---
let scalars = string.unicodeScalars
let unicodeArray = scalars.map({ $0 })
var currentLength: Int = 1
var i = 0
for number in unicodeArray where controlSet.contains(number) {
if i+1 >= unicodeArray.count {
break
}
let nextNumber = unicodeArray[i+1]
if UnicodeScalar(number.value+1) == nextNumber {
currentLength += 1
} else {
currentLength = 1
}
if currentLength >= sequenceLength {
return true
}
i += 1
}
return false
}
I did assumed that "a" ... "z" and "A"..."Z" are consecutive here, to make it in range, but it may be better do explicitly list all the symbols you want.
Or use CharacterSet.alphanumerics, but is not limited to basic latin alphabet.

Swift 3 conversion - 'predecessor()' is unavailable

I am getting the above error. So how do we convert the following codes to swift 3 compatible?
let charactersAreInCorrectState = { () -> Bool in
let previousContext = self.textDocumentProxy.documentContextBeforeInput
if previousContext == nil || (previousContext!).characters.count < 3 {
return false
}
var index = previousContext!.endIndex
index = index.predecessor()
if previousContext![index] != " " {
return false
}

NilLiteralConvertible in Property setter

In swift I have this:
///3.5.1.8 Range is ± 32,576 FPM, FPM of 32640 means max. Also can be invalid (nil)
var vVelcotiy: Int? {
get {
let ret : Int16 = decode12Bit2sCompliment(bytes[15], bytes[16], useEntireFirstByte: false)
return Int(ret * 64);
}
set {
if (bytes[15] == 8 && bytes[16] == 0) {
return nil
}
if let n = newValue {
let nv = n / 64
bytes[15] = (bytes[15] & 0xF0) | (UInt8(nv) >> 8)
bytes[16] = UInt8(nv)
} else {
bytes[15] = (bytes[15] & 0xF0) | 0xF8
bytes[16] = 0x00
}
}
}
I'm getting an error of type '()' does not conform to protocol 'NilLiteralConvertible' but I've declared my property as optional so I'm confused.
I'm hoping to be able to do:
var a : vVelocity = nil
Reading rintaro's answer and taking my comment into consideration, I think you've misplaced the first check in the setter, it looks like it belongs in the getter instead:
var vVelcotiy: Int? {
get {
if (bytes[15] == 8 && bytes[16] == 0) {
return nil
}
let ret : Int16 = decode12Bit2sCompliment(bytes[15], bytes[16], useEntireFirstByte: false)
return Int(ret * 64);
}
set {
if let n = newValue {
let nv = n / 64
bytes[15] = (bytes[15] & 0xF0) | (UInt8(nv) >> 8)
bytes[16] = UInt8(nv)
} else {
bytes[15] = (bytes[15] & 0xF0) | 0xF8
bytes[16] = 0x00
}
}
}
Now your getter has a possibility of returning nil, and your setter doesn't depend on the existing value.
The error is here:
set {
if (bytes[15] == 8 && bytes[16] == 0) {
return nil // <--- HERE
}
You cannot return anything from set { }. If you want to break, just return instead.
set {
if (bytes[15] == 8 && bytes[16] == 0) {
return
}