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"]
Related
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?
i wrote code to get character when user enter in text field and do math with them
this :
#IBOutlet weak internal var textMeli: UITextField!
var myChar = textMeli.text
var numb = [myChar[0]*3 , myChar[1]*7]
but one is wrong
textMeli.text is a String.
myChar is a String.
You can't access a Character from a String using bracket notation.
Take a look at the documentation for the String structure.
You'll see that you can access the string's characters through the characters property. This will return a collection of Characters. Initalize a new array with the collection and you can then use bracket notation.
let string = "Foo"
let character = Array(string.characters)[0]
character will be of type Character.
You'll then need to convert the Character to some sort of number type (Float, Int, Double, etc.) to use multiplication.
Type is important in programming. Make sure you are keeping track so you know what function and properties you can use.
Off the soap box. It looks like your trying to take a string and convert it into a number. I would skip the steps of using characters. Have two text fields, one to accept the first number (as a String) and the other to accept the second number (as a String). Use a number formatter to convert your string to a number. A number formatter will return you an NSNumber. Checking out the documentation and you'll see that you can "convert" the NSNumber to any number type you want. Then you can use multiplication.
Something like this:
let firstNumberTextField: UITextField!
let secondNumberTextField: UITextField!
let numberFormatter = NumberFormatter()
let firstNumber = numberFormatter.number(from: firstNumberTextField.text!)
let secondNumber = numberFormatter.number(from: secondNumberTextField.text!)
let firstInt = firstNumber.integerValue //or whatever type of number you need
let secondInt = secondNumber.integerValue
let product = firstInt * secondInt
Dealing with Swift strings is kind of tricky because of the way they deal with Unicode and "grapheme clusters". You can't index into String objects using array syntax like that.
Swift also doesn't treat characters as interchangeable with 8 bit ints like C does, so you can't do math on characters like you're trying to do. You have to take a String and cast it to an Int type.
You could create an extension to the String class that WOULD let you use integer subscripts of strings:
extension String {
subscript (index: Int) -> String {
let first = self.startIndex
let startIndex = self.index(first, offsetBy: index)
let nextIndex = self.index(first, offsetBy: index + 1)
return self[startIndex ..< nextIndex]
}
}
And then:
let inputString = textMeli.text
let firstVal = Int(inputString[0])
let secondVal = Int(inputString[2])
and
let result = firstVal * 3 + secondVal * 7
Note that the subscript extension above is inefficient and would be a bad way to do any sort of "heavy lifting" string parsing. Each use of square bracket indexing has as bad as O(n) performance, meaning that traversing an entire string would give nearly O(n^2) performance, which is very bad.
The code above also lacks range checking or error handling. It will crash if you pass it a subscript out of range.
Note that its very strange to take multiple characters as input, then do math on the individual characters as if they are separate values. This seems like really bad user interface.
Why don't you step back from the details and tell us what you are trying to do at a higher level?
I will get a lot of message string
Like these:
1.hello {{http://i.imgur.com/f1cqT3ut.jpg}} world {{http://i.imgur.com/f1cqT3ut.jpg}}
2.hi {{http://i.imgur.com/iVx9iqjt.jpg}} {{http://i.imgur.com/iVx9iqjt.jpg}} how {{http://i.imgur.com/ZpXgxiXt.jpg}} are {{http://i.imgur.com/rcdHObKt.jpg}} you {{http://i.imgur.com/yX5dHdet.jpg}} ? {{http://i.imgur.com/2iZSBKGt.jpg}}
And I want to handle these messages
Like these:
1.message handled 1
2.message handled 2
Now I only know can use NSMutableAttributedString to show all handled messages and use NSTextAttachment to show the url images.
But I don't know how to replace and handle these messages.
Help me, please.
Thanks.
If you can assume that each string will be setup like that, where the words and URL's are separated by spaces - and the URL's are all contained within two sets of curly brackets, you could create a method that would then take a string and split it into an array of substrings (separated by spaces), you could then check for a substring that starts with "{{" to know it's a URL. I just wrote something like this which would return an array of tuples where each tuple is an integer (correlating to the index of the URL within the array of substrings), and a string which represents the URL removed from the curly brackets.
func split(_ s: String) -> [(Int, String)] {
// Separate the original string into an array of substrings separated by a space
let separated = s.components(separatedBy: " ")
// Filter the separated array to find the URLs that start with {{
var urls = separated.filter{ $0.hasPrefix("{{") }
// Map the urls array to get an array of ints correlating to their respective indices from the separated array
let indicies = urls.map { separated.index(of: $0) }
// create an empty array of Int and String tuples
var tuples: [(Int, String)] = []
// Loop through the url array
for i in 0 ..< urls .count {
// Remove the left side (open) curly brackets
urls[i] = urls[i].replacingOccurrences(of: "{{", with: "")
// Remove the right side (close) curly brackets
urls[i] = urls[i].replacingOccurrences(of: "}}", with: "")
// Append the tuple with the url's index from the separated array and it's actual url value as a string
tuples.append((indicies[i]!, urls [i]))
}
return tuples
}
You could then use this to split the words from the urls, and then fetch the images (that would be up to you - maybe use Alamofire or even just NSURLSession) and then since you have their original index from the array of substrings - you still know what order they go in. So re-arrange them based on original order once the asynchronous request comes back, and then use UILabels sandwiched in between UIImageViews (or vice-versa) to display the content in the way you're trying.
let fullString = NSMutableAttributedString(string : "start of text")
let image1Attachment = NSTextAttachment()
image1Attachment.image = UIImage(named : "image name")
let image1String = NSAttributedString(attachment: image1Attachment)
fullString.append(image1String)
fullString.append(NSAttributedString(string: "End of text"))
yourLabel.attributedText = fullString
This code is to shows a way that you want.Use for reference implement code as you need.
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)")
}
I saw a question: Swift: Split a String into an array
And there's some code I don't understand:
let fullName = "First Last"
let fullNameArr = split(fullName.characters){$0 == " "}.map{String($0)}
fullNameArr[0] // First
fullNameArr[1] // Last
How does split() and map{} work?
You're using a syntax that won't work in Xcode7. The correct syntax should be
let fullNameArr = fullName.characters.split{$0 == " "}.map(String.init)
Getting that out of the way let's break down that line into two pieces:
split takes
A collection of Characters representing the String's extended
grapheme clusters
-- From Xcode docs
and a closure taking a character and returning Bool - true if the character can be considered as a separator.
if this syntax is confusing try reading that:
fullNameArr = fullName.characters.split({
character in
return character == " "
})
Now, split returns an array of SubSequence objects. You want to convert them back to string to be able to print them nicely. So one way of doing it would be creating a for loop iterating over all the results of split and converting them to string, then appending to a result array, or using map method that does the same.
If you look closely at the first line, you execute map on the array and pass a closure that does something with every element of the array and writes it back.
A simple example how that works
let exampleArray = [1, 2, 3]
print(exampleArray.map {$0 * 3})
// prints [3, 6, 9]
Hope that helps!