How to fix deprecated substring(with: ) - swift

I'm working through a book exercise where the author has the following code.
func getMatchingString(str: String) -> String? {
if let newMatch = str.range(of:regExFindMatchString,
options:.regularExpression) {
return str.substring(with: newMatch)
} else {
return nil
}
}
the str.substring(with: newMatch) line shows 'substring(with:) is deprecated use String slicing subscript.'
I've tried to figure out what to use to fix this but everything I've tried shows I just don't understand this well enough to fix it. I know that the newMatch is a range object, just can't figure out how to use it effectively.
Any help is greatly appreciated..
Bob

Just use subscripting with the range you obtain from the if let
if let newMatchRange = str.range(of:regExFindMatchString, options:.regularExpression) {
return String(str[newMatchRange])
} else {
return nil
}
You need to translate it to a String as the method actually returns a Substring type, not a String.

Related

What am I missing in my random lowercase string generator function ? Using Swift 5.5

I have a function I use to generate random strings for email addresses or passwords (for example). It was originally set like this:
static func random(length: Int) -> String {
let characters = "abcdefghijklmnopqrstuvwxyz"
return String((0..<length).map { _ in characters.randomElement()! })
}
So I changed it to this:
static func random(length: Int) -> String {
let characters = CharacterSet.lowercaseLetters
return String((0..<length).map { _ in characters.randomElement()! })
}
But I get an error saying "Value of type 'CharacterSet' has no member 'randomElement'.
I'm very new to Swift and I've done a lot of searching and so far I haven't found a good solution. I want to keep this function short and sweet. And I've been at this for a while now. Any help would be greatly appreciated! Please let me know if any more context is needed.
Edit: My question got closed because it was seen as a duplicate but, I looked at the solution page and tried to apply it to my issue and still no resolution. I'm not sure if that's because the previous answers are from 2015 and older or they were for obj-c
As I said in my comment of the possible duplicated post you can use that extension from the accepted answer to get all characters from a CharacterSet and get a randomElement from the resulting collection. Also as stated in the accepted answer some characters may not be present in the font used to display the result:
extension CharacterSet {
var array: [Character] {
var result: [Character] = []
for plane: UInt8 in 0...16 where hasMember(inPlane: plane) {
for unicode in UInt32(plane) << 16 ..< UInt32(plane + 1) << 16 {
if let uniChar = UnicodeScalar(unicode), contains(uniChar) {
result.append(Character(uniChar))
}
}
}
return result
}
}
let lowercaseLettersArray = CharacterSet.lowercaseLetters.array
let randomCharacter = lowercaseLettersArray.randomElement()! // "ᵳ"

Swift return values of different types in function based on conditions

I am new in Swift and have a small question.
I want to build a function which can return values of different types based on the conditions. What return type should I use?? Below is the function. I use "??" as the placeholder. Can anybody help to change the "??" with correct return type?? Thanks!!
fun Req_amt() -> ?? {
if let input_amt = readLine() {
if let amount = Float(input_amt) {
return amount
} else {
return "Bad number."
}
} else {
return "Bad input."
}
}
You could return a Float? with nil to signify an error in general, or you could return a Float but with throws and throw an Error to give further specific info such as “Bad number” or “Bad input”. It sounds like the latter is what you want here.

Remove specific characters from a String using an extension

I’ve found this awesome extension that remove everything except the characters in the quotation marks.
extension String.UnicodeScalarView {
var removeCharacters: String {
return String(filter(("cfh".unicodeScalars).contains))
}
}
print("abcd123efg".unicodeScalars.removeCharacters) // it prints “cf”, my desirable result is to make it print “abd123eg”
It prints “cf”, my desirable result is to make it print “abd123eg”.
Can you help me invert it to remove only the characters that are between the quotation marks and leave everything else?
Note:It is also important that it recognize (unicodeScalars) so please don’t remove this part.
You need to negate the call to contains:
return String(filter { !"cfh".unicodeScalars.contains($0) })
Taking #rmaddy into consideration, if you are using extension then make sure you think about generics and work in any case. Like you have kept "cfh" as a static String, what if you want to remove "abc", then it won't work. So, here is the modified version:
extension String.UnicodeScalarView {
func removeCharacters(_ characters: String) -> String {
return String(filter { !characters.unicodeScalars.contains($0) })
}
}
Usage: "abcd123efg".unicodeScalars.removeCharacters("cfh")
Create an extension for String like below
extension String {
func removeGroupOfCharacters(removalString : String) -> String {
// return an Array without the removal Characters
let filteredCharacters = Array(self).filter { !Array(removalString).contains($0) }
// build a String with the filtered Array
let filtered = String(filteredCharacters)
return filtered
}
}
override func viewDidLoad() {
super.viewDidLoad()
let unfiltered = "abcd123efg"
let removal = "cfh"
print(unfiltered.removeGroupOfCharacters(removalString: removal))
// => output will be like this "abd123eg\n"
}
It's a basic example. You can do like that.
extension String {
return aString.replacingOccurrences(of: "X", with: "")
}

Substrings in Swift

I'm having a problem with understand how I can work with substrings in Swift. Basically, I'm getting a JSON value that has a string with the following format:
Something
I'm trying to get rid of the HTML anchor tag with Swift so I'm left with Something. My thought was to find the index of every < and > in the string so then I could just do a substringWithRange and advance up to the right index.
My problem is that I can't figure out how to find the index. I've read that Swift doesn't support the index (unless you extend it.)
I don't want to add CPU cycles unnecessarily. So my question is, how do I find the indexes in a way that is not inefficient? Or, is there a better way of filtering out the tags?
Edit: Converted Andrew's first code sample to a function:
func formatTwitterSource(rawStr: String) -> String {
let unParsedString = rawStr
var midParseString = ""
var parsedString = ""
if let firstEndIndex = find(unParsedString, ">") {
midParseString = unParsedString[Range<String.Index>(start: firstEndIndex.successor(), end: unParsedString.endIndex)]
if let secondStartIndex = find(midParseString, "<") {
parsedString = midParseString[Range<String.Index>(start: midParseString.startIndex, end: secondStartIndex)]
}
}
return parsedString
}
Nothing too complicated. It takes in a String that has the tags in it. Then it uses Andrew's magic to parse everything out. I renamed the variables and made them clearer so you can see which variable does what in the process. Then in the end, it returns the parsed string.
You could do something like this, but it isn't pretty really. Obviously you would want to factor this into a function and possibly allow for various start/end tokens.
let testText = "Something"
if let firstEndIndex = find(testText, ">") {
let testText2 = testText[Range<String.Index>(start: firstEndIndex.successor(), end: testText.endIndex)]
if let secondStartIndex = find(testText2, "<") {
let testText3 = testText2[Range<String.Index>(start: testText2.startIndex, end: secondStartIndex)]
}
}
Edit
Working on this a little further and came up with something a little more idiomatic?
let startSplits = split(testText, { $0 == "<" })
let strippedValues = map(startSplits) { (s) -> String? in
if let endIndex = find(s, ">") {
return s[Range<String.Index>(start: endIndex.successor(), end: s.endIndex)]
}
return nil
}
let strings = map(filter(strippedValues, { $0 != "" })) { $0! }
It uses a little more functional style there at the end. Not sure I much enjoy the Swift style of map/filter compared to Haskell. But anyhow, the one potentially dangerous part is that forced unwrapping in the final map. If you can live with a result of [String?] then it isn't necessary.
Even though this question has been already answered, I am adding solution based on regex.
let pattern = "<.*>(.*)<.*>"
let src = "Something"
var error: NSError? = nil
var regex = NSRegularExpression(pattern: pattern, options: .DotMatchesLineSeparators, error: &error)
if let regex = regex {
var result = regex.stringByReplacingMatchesInString(src, options: nil, range: NSRange(location:0,
length:countElements(src)), withTemplate: "$1")
println(result)
}

Swift instr or strpos Equivalent

I've searched and searched but can't see to find what the instr or strpos equivalent in Swift is. Just need to see if a string contains a string. How can I do this in Swift?
Here is a useful extension of String in Swift. Both functions work like the well known PHP functions. Just paste this code in any .swift file of your project:
import Foundation
extension String {
func strpos(needle:String)->Int{
//Returns the index of the first occurrence of a substring in a string, or -1 if absent
if let range = self.rangeOfString(needle) {
return startIndex.distanceTo(range.startIndex)
} else {
return -1
}
}
func instr(needle:String)->Bool{
return self.containsString(needle)
}
}
Usage, anywhere else in your projet
let myString = "Hello, world"
print(myString.strpos("world")) //->prints "7"
print(myString.strpos("Dolly")) //->prints "-1"
print(myString.strpos(",")) //->prints "5"
Use rangOfString():
if string.rangeOfString("mySubstring") != nil
{
println("string contains substring")
}