how do I properly express this 'rangeOfCharacter' statement using swift 3? - ios

I have some logic that allows me to listen to the editing of a textfield for invalid characters from a character set I created, obviously do to the rearrangement in swift 3 syntax, I get the following error:
Cannot invoke initializer for type 'Range<Index>' with an argument list of type '(DefaultBidirectionalIndices<String.CharacterView>)
on this line of code:
if let _ = string.rangeOfCharacter(from: invalidCharacters, options: [], range:Range<String.Index>(string.characters.indices))
I've looked into the new API doc's but can't seem to find a correct formatting for this line in swift 3... any suggestions?

You just need to use ..< operator to create your range. Note: If you want to check the whole string you can omit the options and range parameters.
if let _ = string.rangeOfCharacter(from: invalidCharacters, options: [], range: string.startIndex..<string.endIndex) {
}
Or simply:
if let _ = string.rangeOfCharacter(from: invalidCharacters) {
}

Related

Non-optional expression of type 'String' used in a check for optionals

I am getting this warning from Xcode Swift 5, here is my code I don't get what is wrong, I use this to remove any new line or tab at the end of my String (line)
My code:
let url: String = String(line.filter { !" \n\t\r".contains($0) })
UPDATE
I was doing it inside an if let and was using the type cast operator here is the solution and the rest of code and an example of the line value.
let line = " http://test.com/testing.php \n"
if let url: String = line.filter({!" \n\t\r".contains($0)}) as String?
{
//More action here
}
Thank you
to me this line looks good, but you may be missing the parentheses for the string filter method. Here's two ways I did it in playground. Let me know if this works for you, or how I can help further.
var line = "\t Hello, line removal \n \t Another new line \n"
let filteredClosure = line.filter { (char) -> Bool in
return !"\n\t\r".contains(char)
}
let filterShorthand = line.filter({!"\n\t\r".contains($0)})
With the line you provided, I would expect white-space to be removed too. If that's what you're looking for, add a space inside the filter string: " \n\t\r"

How to fix the Strideable protocol error?

I have the following code, but the compiler gives an error
Type 'String.Index' does not conform to protocol 'Strideable'
While I was looking for, I encountered many similar questions, tried several suggested options - but this did not help get rid of the problem.
I'm sorry, I'm not very good at this and just trying to run the code of old version of Swift in my Swift 4 project.
Error on the line
roz.endIndex
let t = myHTMLString
let rangeOfZero = t.range(of: "[\"fmt_stream_map\"", options: .backwards)
if let roz = rangeOfZero {
if let suffix = t.characters.suffix(roz.endIndex) {
first = suffix
}
}
I suppose you want to get the substring from the end of the found range to the end of the string.
In Swift 4 you can use
let t = myHTMLString
if let roz = t.range(of: "[\"fmt_stream_map\"", options: .backwards) {
first = String(t[roz.upperBound...])
}

Find a word after and before a string

I have a string like so...
ab-0-myCoolApp.theAppAB.in
How can I get the word myCoolApp from this string...? Also there are many strings in the same format i.e myCoolApp can be myCoolAppABX or myCoolAppABCD etc.
that could be a really brief solution (=one of the many ones) to your problem, but the core concept would be something like that in every case.
the input has some random values:
let inputs = ["ab-0-myCoolApp.theAppAB.in", "ab-0-myCoolAppABX.theAppAB.in", "ab-0-myCoolAppABXC.theAppAB.in"]
and having a regular expression to find matches:
let regExp = try? NSRegularExpression(pattern: "-([^-]*?)\\.", options: NSRegularExpression.Options.caseInsensitive)
then Release the Kraken:
inputs.forEach { string in
regExp?.matches(in: string, options: NSRegularExpression.MatchingOptions.reportProgress, range: NSMakeRange(0, string.lengthOfBytes(using: .utf8))).forEach({
let match = (string as NSString).substring(with: $0.range(at: 1))
debugPrint(match)
})
}
finally it prints out the following list:
"myCoolApp"
"myCoolAppABX"
"myCoolAppABXC"
NOTE: you may need to implement further failsafes during getting the matches or you can refactor the entire idea at your convenience.

Using Regular Expressions to Extract a Value in iOS Swift

I want to extract Vimeo Id from its URL. I have tried to many solutions but not found what I exactly want for swift. I refer to many questions and found one solution in JAVA. I want same behaviour in iOS swift so I can extract the ID from matched group array.
Using Regular Expressions to Extract a Value in Java
I use following vimeo URL regex and I want group-3 if string matched with regex:
"[http|https]+:\/\/(?:www\.|player\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)([a-zA-Z0-9_\-]+)(&.+)?"
Test Vimeo URL: https://vimeo.com/62092214?query=foo
let strToTest = "https://vimeo.com/62092214?query=foo"
let pattern = "[http|https]+:\\/\\/(?:www.|player.)?vimeo.com\\/(?:channels\\/(?:\\w+\\/)?|groups\\/([^\\/]*)\\/videos\\/|album\\/(\\d+)\\/video\\/|video\\/|)([a-zA-Z0-9_\\-]+)(&.+)?"
let regex = try! NSRegularExpression.init(pattern: pattern, options: [])
let match = regex.firstMatch(in: strToTest, options: [], range: NSRange.init(location: 0, length: strToTest.count))
let goup3Range = match?.range(at: 3)
let substring = (strToTest as NSString).substring(with: goup3Range!)
print("substring: \(substring)")
That should work.
You need to escape all \ in the pattern.
You need to call range(at:) to get the range of the group you want according to your pattern (currently group3), then substring.
What should be improved?
Well, I did all sort of force unwrapped (every time I wrote a !). for the sake of the logic and not add do/catch, if let, etc. I strongly suggest you check them carefully.
Here is yet another version. I am using named capturing group, a bit different than the answer provided by Larme.
let regex = "[http|https]+:\\/\\/(?:www\\.|player\\.)?vimeo\\.com\\/(?:channels\\/(?:\\w+\\/)?|groups\\/(?:[^\\/]*)\\/videos\\/|album\\/(?:\\d+)\\/video\\/|video\\/|)(?<vimeoId>[a-zA-Z0-9_\\-]+)(?:&.+)?"
let vimeoURL = "https://vimeo.com/62092214?query=fooiosiphoneswift"
let regularExpression = try! NSRegularExpression(pattern: regex,
options: [])
let match = regularExpression.firstMatch(in: vimeoURL,
options: [],
range: NSRange(vimeoURL.startIndex ..< vimeoURL.endIndex,
in: vimeoURL))
if let range = match?.range(withName: "vimeoId"),
let stringRange = Range(range, in: vimeoURL) {
let vimeoId = vimeoURL[stringRange]
}
Also, please check that I have modified your regex a bit, such that everything else except vimeoId are non-capturing.

`CountedSet` initialization issue

I'm comparing the characters contained within two words. In seeking to accomplish this, Set (aka NSSet) seemed like the way to go to accomplish this task. I've discovered it returns false positives on matches, so I am attempting to use CountedSet (aka NSCountedSet) instead.
I'm able to initialize a Set without issue, but I can't get the CountedSet initializer to work. Here's what I've done...
I start with a String:
// Let's say myTextField.text = "test"
let textFieldCharacters = myTextField.text?.characters
// word is a string from the ENABLE list of words
let wordCharacters = word.characters
Then I dump the characters into an Array:
var wordCharactersArray = [Character]()
for character in wordCharacters {
wordCharacterArray.append(character)
}
var textFieldCharactersArray = [Character]()
for character in textFieldCharacters {
wordCharacterArray.append(character)
}
Then I create a Set from the character arrays:
let textFieldSet = Set<Character>(textFieldCharactersArray)
let wordSet = Set<Character>(wordCharactersArray)
Finally, I test to see if the textFieldSet is a superSet of wordSet with the following:
textFieldSet.isSuperset(of: wordSet)
Going back to my example, if myTextField.text is "test", I'm returning values for word whose characters are a superset of the wordSet, but the counts of the individual elements don't match the character counts of myTextField.text
In researching my issue, I've found CountedSet (fka NSCountedSet), which I think would resolve my issue. It has two method signatures:
public convenience init(array: [AnyObject])
public convenience init(set: Set<NSObject>)
I've tried initializing the 2 sets of characters like so:
let textFieldSet = CountedSet(array: textFieldCharacterArray)
let wordSet = CountedSet(array: wordCharacterArray)
I get the following error for the sets
Cannot convert value of type '[Character]' to expected argument type
'[AnyObject]'.
So I tried initializing the set like this:
let textFieldSet = CountedSet(array: textFieldCharacterArray as! [AnyObject])
Which yields the following error:
'AnyObject' is not a subtype of 'Character'
I've also tried to initialize the CountedSet with a Set, per the method signature, but I get errors when I try to do that, too.
Any suggestions how to initialize a CountedSet would be greatly appreciated.
You are correct that if you need to compare not just the presents of elements but also their count, you should use CountedSet, which is a renaming of NSCountedSet for swift 3.0. The problem you are running into is CountedSet can only accept elements that are objects and Characters are not. As Eric D points out in their comment, the easies way to get around this is by mapping your [Character] to [String] which will bridge to [NSString].
You are not running into this problem using Set, because it is a native Swift collection type that initialize with elements of any type. This is why you can initialize a Set with [Character].
To see the difference:
let word = "helo"
let wordCharacters = Array(word.characters)
let wordSet = Set(wordCharacters)
let wordCharStrings = wordCharacters.map{String($0)}
let wordCountedSet = CountedSet(array: wordCharStrings)
let textField = "hello"
let textFieldCharacters = Array(textField.characters)
let textSet = Set(textFieldCharacters)
let textFieldCharStrings = textFieldCharacters.map{String($0)}
let textFieldCountedSet = CountedSet(array: textFieldCharStrings)
textFieldCountedSet.isSubset(of: wordCountedSet as! Set<NSObject>) // returns false, but if word had two or more l's it would return true
textSet.isSubset(of: wordSet) // returns true

Resources