Split String with varied amount of input data - swift

I have a string that looks like this:
https://product/000000/product-name-type-color
I used a split to separate this strings, but Im having problems because the link can come without the description or the id
guard let separateLink = deeplink?.split(separator: "/") else { return }
let linkWithoutProductDetails = "\(separateLink[0] ?? "")//\(separateLink[1] ?? "")/\(separateLink[2] ?? "")"
When the link comes only https://product/ Im getting Fatal error: Index out of range even using the Optionals and String Interpolation, how can i guarantee that independently of the quantity of informations in my link the code wont break

You should check the number of path components. However, ideally you should use the URL functions instead of manipulating the link as a String:
if var url = URL(string: "https://product/000000/product-name-type-color") {
let pathComponents = url.pathComponents
// "product" is not a path component, it's the host.
// Path components are "/", "000000" and "product-name-type-color"
if pathComponents.count > 2 {
url = url.deletingLastPathComponent()
}
print(url)
}

Related

Get a part of a string that comes before .mp3 but is not always the same link

I want to get only the ID that comes before the .mp3 but after several attempts I can't do it, the link is not always the same length
String examples:
"https://urlexample.com/EXAMPLE_STRING/media/example/audio/20227/07/1657142074431_15789.mp3"
"https://urlexample.com/media/THIS_TEXT_IS_1657130179082_24048.mp3"
The result should be:
"https://urlexample.com/audio/1657130179082_24048"
"https://urlexample.com/audio/THIS_TEXT_IS_1657130179082_24048"
If anyone can help I would appreciate it.
Create a URL with your string then get the id
Code :
let string = "https://urlexample.com/EXAMPLE_STRING/media/example/audio/20227/07/1657142074431_15789.mp3"
guard let url = URL(string: string) else {
// not a url string
return
}
// file name with extension
let fileName = url.lastPathComponent
print(fileName) // 1657142074431_15789.mp3
// file id
let fileId = url.deletingPathExtension().lastPathComponent
print(fileId) // 1657142074431_15789

Extracting string after x number of backlashes in swift

I can't find any way to extract a certain string value from another string in SwiftUi.
It is the following link:
"http://media.site.com/videos/3070/0003C305B74F77.mp4"
How would you go about extracting the numbers 0003C305B74F77?
It would be much easier to treat it as an URL. That's what it is. All you need it to get its last path component after deleting its path extension.
let link = "http://media.site.com/videos/3070/0003C305B74F77.mp4"
if let url = URL(string: link) {
let lastPathComponent = url.deletingPathExtension().lastPathComponent
print(lastPathComponent) // "0003C305B74F77"
}

URL constructor doesn't work with some characters

I'm trying to call a php-script from my app using URLRequest.
The Url path is generated in the String-Variable query and for the request I convert it like this
guard let url = URL(string: query) else {
print("error")
return
}
usually it works, but when the request contains characters like ä, ö, ü, ß the error is triggered. How can I make it work?
The URL(string:) initializer doesn't take care of encoding the String to be a valid URL String, it assumes that the String is already encoded to only contain characters that are valid in a URL. Hence, you have to do the encoding if your String contains non-valid URL characters. You can achieve this by calling String.addingPercentEncoding(withAllowedCharacters:).
let unencodedUrlString = "áűáeqw"
guard let encodedUrlString = unencodedUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: encodedUrlString) else { return }
You can change the CharacterSet depending on what part of your URL contains the characters that need encoding, I just used urlQueryAllowed for presentation purposes.
Split your URL in two separate parts:
let baseURLString = "https://www.example.com"
let pathComponent = "áűáeqw"
let fullURL = URL(string: baseURLString)?.appendingPathComponent(pathComponent)

Delete parameter from URL with swift

I have an URL that looks like myapp://jhb/test/deeplink/url?id=4567 .
I want to delete every thing after the ? char. At the end the URL should look like myapp://jhb/test/deeplink/url. how. can I achieve that? convert the url to a string? Regex?
Use URLComponents to separate the different URL parts, manipulate them and then extract the new url:
var components = URLComponents(string: "myapp://jhb/test/deeplink/url?id=4567")!
components.query = nil
print(components.url!)
myapp://jhb/test/deeplink/url
A convenient extension on URL
private extension URL {
var removingQueries: URL {
if var components = URLComponents(string: absoluteString) {
components.query = nil
return components.url ?? self
} else {
return self
}
}
}
can I achieve that? convert the url to a string? Regex?
When working with URLs, it would be better to treat it as URLComponent:
A structure that parses URLs into and constructs URLs from their
constituent parts.
therefore, referring to URLComponent what are you asking is to remove the the query subcomponent from the url:
if var componenets = URLComponents(string: "myapp://jhb/test/deeplink/url?id=4567") {
componenets.query = nil
print(componenets) // myapp://jhb/test/deeplink/url
}
Note that query is an optional string, which means it could be nil (as mentioned in the code snippet, which should leads to your desired output).
You can do like this
let values = utl?.components(separatedBy: "?")[0]
It will break the string with ? and return the array.
The first object of values give you your resultant string.
You can get each URL component separated from URl using
print("\(url.host!)") //Domain name
print("\(url.path)") // Path
print("\(url.query)") // query string

AppleWatch Messages URL works hard coded but not with variables

TLDR When I hard code phone numbers into a URL it opens in watch messages correctly, but when I use a variable string with the numbers typed in exactly the same way inside of it, it doesn't.
Example:
NSURL(string: "sms:/open?addresses=8888888888,9999999999,3333333333&body=Test")
Above code works but below code doesn't:
let hardCode = "8888888888,9999999999,3333333333"
NSURL(string: "sms:/open?addresses=\(hardCode)&body=Test")
FULL DETAILS:
I am making a URL from variables to open messages on the Apple Watch with pre-filled contents. I am getting the phone numbers from the contact book and storing them in an array. They are provided in this format:
(###) ###-#### but need to be ##########
I tested the code by hard-coding phone numbers into the URL and it works properly with all contacts and completed body:
if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=8888888888,9999999999,3333333333&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}
But when I build the phone number values programmatically it does not work:
//holds phone numbers without special chars
var tempArray: [String] = []
//if I can access the unformatted numbers
if let recips = saveData["recips"] as? [String] {
//for each number provided
recips.forEach { (person: String) in
//remove all non-numerical digits
//person is now (###) ###-####
let newPerson = person.digitsOnly()
//newPerson is ##########
print(person)
print("->\(newPerson)")
//add formatted number to tempArray
tempArray.append(newPerson)
}
}
//combine all numbers with "," between as a string
let recipString = tempArray.joinWithSeparator(",")
//recipString contains ##########,##########,##########...
extension String {
func digitsOnly() -> String{
let stringArray = self.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
return newString
}
}
I then add the "recipString" variable to the NSURL in the below code:
let messageBody = "test"
let urlSafeBody = messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=\(recipString)&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}
The FINAL URL print shows the correct string, but the messages app does not open properly, and shows quick reply menu instead of composed message window. It matches the functioning hard coded number version exactly, but behaves differently.
Totally lost, hope someone can help!
UPDATE 1
Here are the debug prints for both versions of the URL:
Manually declared (not created from recipString but actually declared in the URL string explicitly):
This version works
FINAL URL: sms:/open?addresses=0000000000,1111111111,2222222222,3333333333,4444444444&body=test
Variable created (using recipString):
This version doesn't
FINAL URL: sms:/open?addresses=0000000000,1111111111,2222222222,3333333333,4444444444&body=test
I have also tried applying url encoding to the "recipString" variable by using the below if let:
if let urlSafeRecip = recipString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) {
if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=\(urlSafeRecip)&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}
}
UPDATE 2
I tested to see if the hardcode version of numbers matches the recipString exactly via this code:
let hardCode = "0000000000,1111111111,2222222222,3333333333,4444444444"
let isEqual = (hardCode == recipString)
if isEqual {
print("hardCode matches recipString")
}
else {
print("hardCode does not match recipString")
}
Debug prints:
hardCode matches recipString
UPDATE 3
I have confirmed that:
When a URL is made with hard coded numbers vs. numbers that I make from variables, checking == between them returns true.
In every test I can do between the two version of the url, it matches.
NOTES AFTER CORRECT ANSWER FOUND:
This type of URL formatting will ONLY work with multiple addresses in the URL. If you do not have multiple addresses you will need to do the following, which is undocumented but none-the-less works. I found this by bashing my face on the keyboard for hours, so if it helps you an upvote is deserved :)
follow the answer marked below, and then use this type of logic check before making the URL in the doItButton() function he mentioned:
func setupAndSendMsg(saveData: NSDictionary) {
if let urlSafeBody = createBody(saveData) {
let theNumbers = createNumbers(saveData).componentsSeparatedByString(",")
print(theNumbers.count-1)
if theNumbers.count-1 > 0 {
if let url = NSURL(string: "sms:/open?addresses=\(createNumbers(saveData))&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
} else {
if let url = NSURL(string: "sms:/open?address=\(createNumbers(saveData)),&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
}
}
}
My guess is that it is not the acctual openSystemUrl call that is the problem. I believe there must be something with the code that is building the number string programmatically.
The code bellow is a simplified version of all the code you have posted. I have confirmed that it is working on my Apple Watch. It opens the Messages app with pre-populated numbers & body text.
Take one more look at your code and see if there is something your missing. If you can't find anything, just delete the code and re-write it, probably will be faster then spotting the weird issue.
Once again the code bellow is confirmed working as expected, so you should be able to get it to work. (or just copy & paste my code) :)
class InterfaceController: WKInterfaceController {
#IBAction func doItButton() {
if let urlSafeBody = createBody() {
if let url = NSURL(string: "sms:/open?addresses=\(createNumbers())&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
}
}
private func createBody() -> String? {
let messageBody = "hello test message"
return messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
}
private func createNumbers() -> String {
let numbers = ["(111) 222-3333", "(444) 555-6666"]
var tempArray: [String] = []
numbers.forEach { (number: String) in
tempArray.append(number.digitsOnly())
}
return tempArray.joinWithSeparator(",")
}
}
extension String {
func digitsOnly() -> String{
let stringArray = self.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
return newString
}
}
With above said I would recommend against using undocumented Apple features for anything you plan on putting on the App Store for the reasons already mentioned in comments.