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

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"

Related

Hangman Program 2

I have asked a question before about this program, but it seems that not all problems are resolved. I am currently experiencing an error that states: "Cannot convert value of type 'String' to expected argument type '_Element' (aka 'Character') on the "guard let indexInWord" line:
guard let letterIndex = letters.indexOf(sender)
else { return }
let letter = letterArray[letterIndex]
guard let indexInWord = word.characters.indexOf(letter)
else {
print("no such letter in this word")
return
}
// since we have spaces between dashes, we need to calc index this way
let indexInDashedString = indexInWord * 2
var dashString = wordLabel.text
dashString[indexInDashedString] = letter
wordLabel.text = dashString
I tried converting the String 'letter' to Character but it only resulted in more errors. I was wondering how I can possibly convert String to argument type "_Element." Please help.
It is hard to treat a string like a list in swift, mostly because the String.characters is not a typical array. Running a for loop on that works, but if you are looking for a specific character given an index, it is a bit more difficult. What I like doing is adding this function to the string class.
extenstion String {
func getChars() -> [String] {
var chars:[String] = []
for char in characters {
chars.append(String(char))
}
return chars
}
}
I would use this to define a variable when you receive input, then check this instead of String.characters

How to avoid an error due to special characters in search string when using Regex for a simple search in Swift?

I'm using Regex to search for a word in a textView. I implemented a textField and two switch as options (Whole words and Match case). All work fine when you enter a plain word in the search filed but I get an error when I enter a special character like \ or *.
The error I get is like this one:
Error Domain=NSCocoaErrorDomain Code=2048 "The value “*” is invalid." UserInfo={NSInvalidValue=*}
Is there a way to avoid this problem and have the code handle all the text like plain text?
Because I would like to search also for special characters, I would like to prefer to not interdict to enter them. At the beginning I though to programmatically add an escape backslash to all special character before to perform a search, but maybe there are some more smart approaches?
Here is the code I'm using (based on this tutorial: NSRegularExpression Tutorial: Getting Started)
struct SearchOptions {
let searchString: String
var replacementString: String
let matchCase: Bool
let wholeWords: Bool
}
extension NSRegularExpression {
convenience init?(options: SearchOptions) {
let searchString = options.searchString
let isCaseSensitive = options.matchCase
let isWholeWords = options.wholeWords
// handle case sensitive option
var regexOption: NSRegularExpressionOptions = .CaseInsensitive
if isCaseSensitive { // if it is match case remove case sensitive option
regexOption = []
}
// put the search string in the pattern
var pattern = searchString
// if it's whole word put the string between word boundary \b
if isWholeWords {
pattern = "\\b\(searchString)\\b" // the second \ is used as escape
}
do {
try self.init(pattern: pattern, options: regexOption)
} catch {
print(error)
}
}
}
You may use NSRegularExpression.escapedPatternForString:
Returns a string by adding backslash escapes as necessary to protect any characters that would match as pattern metacharacters.
Thus, you need
var pattern = NSRegularExpression.escapedPatternForString(searchString)
Also, note that this piece:
if isWholeWords {
pattern = "\\b\(searchString)\\b"
might fail if a user inputs (text) and wishes to search for it as a whole word. The best way to match whole words is by means of lookarounds disallowing word chars on both ends of the search word:
if isWholeWords {
pattern = "(?<!\\w)" + NSRegularExpression.escapedPatternForString(searchString) + "(?!\\w)"

Replaced String in Swift 2

So I'm trying to build my app for iOS 9 and am running into one problem. Before, I had a button that would take the string from a label and add it to a string that would take a person to lmgtfy and automatically search for the contents of the string, but now I'm running into an error with map(). Here is the code that worked in iOS 8:
#IBAction func googleButton() {
let replaced = String(map(originalString.generate()) { $0 == " " ? "+" : $0 })
if let url = NSURL(string: "http://google.com/?q=\(replaced)") {
UIApplication.sharedApplication().openURL(url)
}
print(replaced)
}
So now the error I'm getting says, "'map' is unavailable: call the 'map()' method on the sequence." Any ideas? Also, I'm not positive that link will work because it is supposed to be lmgtfy but I couldn't submit this question unless I changed the URL to google.
As of Swift 2, String no longer conforms to SequenceType, therefore you can't call generate on it. Instead you need to use the characters property to obtain a String.CharacterView, which does conform to SequenceType.
Also with Swift 2: map is a method in an extension of SequenceType. Therefore you call it like a method, instead of a free function:
let str = "ab cd ef gh"
let replaced = String(str.characters.map { $0 == " " ? "+" : $0 })
// "ab+cd+ef+gh"
You could also do:
let replaced = str.stringByReplacingOccurrencesOfString(" ", withString: "+")
// "ab+cd+ef+gh"

Formatting strings in Swift

In some languages, like C# for example, you can create a string in the following way:
"String {0} formatted {1} "
And then format it with String.format by passing in the values to format.
The above declaration is good, because you don't have to know of what type its parameters are when you create the string.
I tried to find similar approach in Swift, but what I found out was something like the following format:
"String %d formatted %d"
which requires you to format the string with String(format: , parameters). This is not good because you would also have to know parameter types when declaring the string.
Is there a similar approach in Swift where I wouldn't have to know the parameter types?
Use this one:
let printfOutput = String(format:"%# %2.2d", "string", 2)
It's the same as printf or the Obj-C formatting.
You can also mix it in this way:
let parm = "string"
let printfOutput = String(format:"\(parm) %2.2d", 2)
Edit: Thanks to MartinR (he knows it all ;-)
Be careful when mixing string interpolation and formatting. String(format:"\(parm) %2.2d", 2) will crash if parm contains a percent character. In (Objective-)C, the clang compiler will warn you if a format string is not a string literal.
This gives some room for hacking:
let format = "%#"
let data = "String"
let s = String(format: "\(format)", data) // prints "String"
In contrast to Obj-C which parses the format string at compile time, Swift does not do that and just interprets it at runtime.
In Swift, types need to conform to the CustomStringConvertible protocol in order to be used inside strings. This is also a requirement for the types used in string interpolation like this:
"Integer value \(intVal) and double value \(doubleVal)"
When you understand the CustomStringConvertible, you can create your own function to fulfill your needs. The following function formats the string based on the given arguments and prints it. It uses {} as a placeholder for the argument, but you can change it to anything you want.
func printWithArgs(string: String, argumentPlaceHolder: String = "{}", args: CustomStringConvertible...) {
var formattedString = string
// Get the index of the first argument placeholder
var nextPlaceholderIndex = string.range(of: argumentPlaceHolder)
// Index of the next argument to use
var nextArgIndex = 0
// Keep replacing the next placeholder as long as there's more placeholders and more unused arguments
while nextPlaceholderIndex != nil && nextArgIndex < args.count {
// Replace the argument placeholder with the argument
formattedString = formattedString.replacingOccurrences(of: argumentPlaceHolder, with: args[nextArgIndex].description, options: .caseInsensitive, range: nextPlaceholderIndex)
// Get the next argument placeholder index
nextPlaceholderIndex = formattedString.range(of: argumentPlaceHolder)
nextArgIndex += 1
}
print(formattedString)
}
printWithArgs(string: "First arg: {}, second arg: {}, third arg: {}", args: "foo", 4.12, 100)
// Prints: First arg: foo, second arg: 4.12, third arg: 100
Using a custom implementation allows you to have more control over it and tweak its behavior. For example, if you wanted to, you could modify this code to display the same argument multiple times using placeholders like {1} and {2}, you could fill the arguments in a reversed order, etc.
For more information about string interpolation in Swift: https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID292

AS2 - How do you remove part of a string

I want a simple function that can remove part of a string, eg:
var foo="oranges";
trace(removeStrings(foo,'rang'));
I want the above output as 'oes'. Any help will be greatly appreciated.
Thanks in advance
A quick solution for removing substrings is to use split with the string that you want to remove as delimiter and then join the result:
function removeSubString(str, remove):String {
return str.split(remove).join("");
}
Another way to do this is
function removeStrings(originalString, pattern):String
{
return originalString.replace(pattern, "");
}
For more information about Strings in AS3 you can visit:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/String.html
I should mention that the code above is not going to change your String, so if you need to use the property originalString with the new value you should use:
originalString = removeStrings(originalString, pattern);
The second thing that I should mention is that the replace method will replace the first appearance of the pattern, so if you need to replace every match of the pattern you should do something like
while(originalString.search(pattern) != -1)
{
originalString = removeStrings(originalString, pattern);
}
Hope this will help!
Ivan Marinov
I'm using by long time this snippet, which as the advantage to be available to all string objects on your movie:
String.prototype.replace = function(pattern, replacement) {
return this.split(pattern).join(replacement);
}
can be used in this way:
var str = "hello world";
var newstr = str.replace("world", "abc");
trace(newstr);
as you can see the string class have been extended with the replace method.

Resources