Formatting string with %28# in Swift - ios

I am trying to print a string in formatted like " FOO"
in Swift 4. I can do it with chars but I can't do it with a string object.
I tried:
let a = String(format: "%28c", 0x31)
print (a)
// prints " 1"
But this only works with chars, not with strings.
How can I get the same result with strings?

Related

Split a string by an entire word, not just one character

I want to split a str by more than one character but I keep getting errors. Is this even possible? A brief search seems to imply it's not.
I want to do something like this:
let strspl = "test="
let spl : [String] = str.split(separator: Character(strspl), maxSplits: 1).map(String.init)
Error is:
Can't form a Character from a String containing more than one extended grapheme cluster
You can use components(separatedBy:) method to get an array of string by separating a string with a string separator
var str = "another test= long test"
let strspl = "test="
let spl : [String] = str.components(separatedBy: strspl)
print(spl)
["another ", " long test"]

Difference between Swift String Interpolation Prints

I am new to iOS development, while I was going through string interpolation. I want to know the clarification between these print statement's output:
var value = "5"
print("Values is: \(value)")
print("Values is:", value)
print("Values is: " + value)
Output is : Values is: 5
Values is: 5
Values is: 5
Practically all three forms do the same thing.
The differences are
String interpolation syntax. You can put everything within the inner parentheses which responds to the CustomStringConvertible protocol.
Variadic parameter syntax. print is declared func print(_ items: Any...,. Any... means you can pass multiple items comma separated which are treated as array.
String concatenation syntax : The strings are concatenated with the + operator
If 5 was Int rather than String forms 1 and 2 are valid but not form 3
For such a question, we should take a look at print(_:separator:terminator:) parameters:
1) items: is a variadic parameter of type Any, which means that you can pass zero or more items to it. Example:
print() // passing nothing
print("Hello") // passing single item (String)
print(101, 40.45, false, ["Hi", "Greetings"]) // passing multiple items
2) separator: the string to print between each item (as mentioned in its documentation). Example:
print(101, 40.45, false, ["Hi", "Greetings"], separator: " <=> ")
// 101<=>40.45<=>false<=>["Hi", "Greetings"]
3) terminator: the string to print after all items have been printed (as mentioned in its documentation). Example:
print(101, 40.45, false, ["Hi", "Greetings"], terminator: " ==>")
// 101 40.45 false ["Hi", "Greetings"] ==>
Back to your cases:
First, keep in mind that for all of your three cases you are passing only items parameter; It is valid -for sure- because separator and terminator have default values as " " and \n.
Now, for the first and third print statements
print("Values is: \(value)")
print("Values is: " + value)
what happens is: actually you are dealing with Strings, it is not about the print itself. You can do interpolation in strings as well as using the + for concatenating strings without the print:
// interpolation:
let name = "Jack"
let greetingMessage = "Greetings, \(name)"
print(greetingMessage) // => Greetings, Jack
// concatenating:
let concatenated = "Greetings" + ", " + "Sara"
print(concatenated) // => "Greetings" + ", " + "Sara"
Which means that you are passing a single String item, regardless of doing interpolation or concatenation for it.
You could also check The + function implementation in Swift. Basically, it is an append!
The second print statement:
print("Values is:", value)
What happens here is: you are passing two items; According to the default value for separator, the output is:
Values is: 5
As:
Values is: 5
^ ^^
| ||__ item #2
item #1 |
|
default separator (" ")
In this print statement output is the same but there is different like in first statement use \(value) variable within the string data.
The second statement append data in your string value with keep one space
The third statement just concat two value (it does not keep space between two value), In this statement "+" sign used as operator overloading to concat two value
let value = "5"
print("Values is: \(value)") //use variable value within string
print("Values is:", value) //append value, with keep one space
print("Values is: " + value) //just concat two value
var value = "5"
print("Values is: (value)")
// Print the value as a part of the the string. If you use print("Values is:(value)"), it will print the output without space.
print("Values is:", value)
// you do not need to add a separate space to add the value to sting. It will automatically add the value to the string with a space.
print("Values is: " + value)
// It will show error if you use integer value "Binary operator '+' cannot be applied to operands of type 'String' and 'Int'"
otherwise it will work. And if you want to concatenate int with sting you need to do something like below:-
print("Values is: " + String(value))
// it is normal concatenate number with string
All the above will print the exact

Swift: how to suppress interpretation of special characters and provide string literal

The goal is to serialize a Swift object by converting it to a JSON object then converting the JSON object into a JSON string that can be passed over the wire and decoded on the other side.
The problem is producing a valid JSON string.
Newlines must be escaped in a JSON string, but Swift interprets special characters in the escaped string instead of treating the string as a literal.
For example:
let a = "foobar\nhello\nworld"
let escapedString = a.replacingOccurrences(of: "\n", with: "\\n")
print(escapedString)
What gets printed is foobar\nhello\nworld instead of the desired foobar\\nhello\\nworld.
How do you tell Swift to treat a string as a literal and not to interpret special characters within?
UPDATE
As OOPer points out, using debugPrint shows the \\n characters remaining intact.
However, when paired with evaluateJavaScript in WKWebView, the \\n characters are turned into \n, which is the root issue. For example:
let script = "\(callback)(\'\(escapedString)\')"
webView!.evaluateJavaScript(script) { (object: Any?, error: Error?) -> Void in
print("Done invoking \(callback)")
}
There is no unescaped string syntax like in javascript template literals which is probably what you are looking for; maybe they will add it in the future. Unfortunately you therefore have to escape each back slash which sometimes looks very scray, as in your example.
//This is the same as `foobar\nhello\nworld` where each char is a literal
let a = "foobar\\nhello\\nworld"
let escapedString = a.replacingOccurrences(of: "\\n", with: "\\\\n")
//This outputs `foobar\\nhello\\nworld`
print(escapedString)
Maybe you are just mistaking to interpret the output from print.
When you get foobar\nhello\nworld from print(escapedString), escapedString contains 20 characters -- f o o b a r \ n h e l l o \ n w o r l d.
This is a valid JSON string when enclosed between "s.
If you want to check the escaped result in String-literal-like notation, you can use debugPrint:
let a = "foobar\nhello\nworld"
let escapedString = a.replacingOccurrences(of: "\n", with: "\\n")
print(escapedString) //->foobar\nhello\nworld
debugPrint(escapedString) //->"foobar\\nhello\\nworld"
For UPDATE
When using with evaluateJavaScript, you'd better think what is the right code as JavaScript, if you want to represent a JSON escaped string in JavaScript, you would write in .js file (or in <script>...</script>):
someFunc('foobar\\nhello\\nworld');
So, you may need to write something like this:
let a = "foobar\nhello\nworld"
let escapedForJSON = a.replacingOccurrences(of: "\n", with: "\\n")
//In actual code, you may need a little more...
let escapedForJavaScriptString = escapedForJSON.replacingOccurrences(of: "\\", with: "\\\\")
let script = "\(callback)(\'\(escapedForJavaScriptString)\')"
webView!.evaluateJavaScript(script) { (object: Any?, error: Error?) -> Void in
print("Done invoking \(callback)")
}

Invalid escape sequence in literal: "\b"

I need to be able to create a String that is "\b". But when I try to, Xcode throws a compile-time error: Invalid escape sequence in literal. I don't understand why though, "\r" works just fine. If I put "\\b" then that's what is actually stored in the String, which is not what I need - I only need one backslash. To me, this seems to be a Swift oddity because it works just fine in Objective-C.
let str = "\b" //Invalid escape sequence in literal
NSString *str = #"\b"; //works great
I need to generate this string because "\b" is the only way to detect when the user pressed 'delete' when using UIKeyCommand:
let command = UIKeyCommand(input: "\b", modifierFlags: nil, action: "didHitDelete:")
How can I work around this issue?
EDIT: It really doesn't want to generate a String that is only "\b", this does not work - it stays the original value:
var delKey = "\rb"
delKey = delKey.stringByReplacingOccurrencesOfString("r", withString: "", options: .LiteralSearch, range: nil)
The Swift equivalent of \b is \u{8}. It maps to ASCII control code 8, just like \b in Objective C. I've tested this and found it to work fine with UIKeyCommand, in this earlier answer of mine.
Example snippet:
func keyCommands() -> NSArray {
return [
UIKeyCommand(input: "\u{8}", modifierFlags: .allZeros, action: "backspacePressed")
]
}
I don't believe it is supported.
Based on the Swift documentation https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html:
String literals can include the following special Unicode characters:
The escaped special characters \0 (null character), \ (backslash), \t
(horizontal tab), \n (line feed), \r (carriage return), \" (double
quote) and \' (single quote)
An arbitrary Unicode scalar, written as
\u{n}, where n is between one and eight hexadecimal digits
The ASCII for the \b is 8. If you do the following, you'll see these results
let bs = "\u{8}"
var str = "Simple\u{8}string"
println(bs) // Prints ""
println("bs length is \(bs.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))") // Prints 1
println(str) // Prints Simplestring
let space = "\u{20}"
println(space) // Prints " "
println("space length is \(space.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))") // Prints 1
str = "Simple\u{20}string"
println(str) // Prints Simple string
It looks like while ASCII 8 "exists", it is "ignored".

Concatenating variable into literal string

I'm trying to concatenate a variable into a literal string purely for readability purposes e.g.
myString = "test"
myString2 = [[
first part of the string
this is a " .. myString .. " string
last part of the string]]
print(myString2)
but this literally outputs
first part of the string
this is a " .. myString .. " string
last part of the string
I'm sure it's something simple but I've tried Googling to find out how to achieve this and came up blank.
The quotes inside the double bracket delimitors aren't doing anything. The only way to end the double bracket is with a double bracket:
myString2 = [[
first part of the string
this is a ]] .. myString .. [[ string
last part of the string]]
That will give you:
first part of the string
this is a test string
last part of the string
See: http://www.lua.org/pil/2.4.html

Resources