How to replace a substring with a link(http) in swift 3? - swift

I have a string and substring(http) and I want to replace that substring but I don't know when that substring will end. I mean want to check it until one space is not coming and after that I want to replace it.
I am checking that if my string contains http which is also a string then I want to replace it when space will come.
Here below is my example :-
let string = "Hello.World everything is good http://www.google.com By the way its good".
This is my string It can be dynamic also I mean in this above string http is there, so I want to replace "http://www.google.com" to "website".
So it would be
string = "Hello.World everything is good website By the way its good"

A possible solution is Regular Expression
The pattern searches for http:// or https:// followed one or more non-whitespace characters up to a word boundary.
let string = "Hello.World everything is good http://www.google.com By the way its good"
let trimmedString = string.replacingOccurrences(of: "https?://\\S+\\b", with: "website", options: .regularExpression)
print(trimmedString)

Split each words, replace and join back should solve this.
// split into array
let arr = string.components(separatedBy: " ")
// do checking and join
let newStr = arr.map { word in
return word.hasPrefix("http") ? "website" : word
}.joined(separator: " ")
print(newStr)

Related

get substrings from string

I have the following string from a server:
I agree with the <a>((http://example.com)) Terms of Use</a> and I've read the <a>((http://example2.com)) Privacy</a>
now I want to show it like this in a label:
I agree with the Terms of Use and I've read the Privacy
I tried to cut of the ((http://example.com)) from the string and save it in another String. I need the link because the text should be clickable later.
I tried this to get the text that I want:
//the link:
let firstString = "(("
let secondString = "))"
let link = (text.range(of: firstString)?.upperBound).flatMap { substringFrom in
(text.range(of: secondString, range: substringFrom..<text.endIndex)?.lowerBound).map { substringTo in
String(text[substringFrom..<substringTo])
}
}
//the new text
if let link = link {
newString = text.replacingOccurrences(of: link, with: kEmptyString)
}
I got this from here: Swift Get string between 2 strings in a string
The problem with this is that it only removes the text inside the (( )) brackets. The brackets are still there. I tried to play with the offset of the indexes but this doesn't changed anything. Moreover this solution works if there's only one link in the text. If there are multiple links I think they should be stored and I have to loop through the text. But I don't know how to do this. I tried many things but I don't get this working. Is there maybe an easier way to get what I want to do?
You can use a regular expression to do a quick search replace.
let text = "I agree with the <a>((http://example.com)) Terms of Use</a> and I've read the <a>((http://example2.com)) Privacy</a>"
let resultStr = text.replacingOccurrences(of: "<a>\\(\\(([^)]*)\\)\\) ", with: "<a href=\"$1\">", options: .regularExpression, range: nil)
print(resultStr)
Output:
I agree with the Terms of Use and I've read the Privacy
You can use something like this to get the links:
let s = "I agree with the ((http://example.com)) Terms of Use and I've read the ((http://example2.com)) Privacy"
let firstDiv = s.split(separator: "(") // ["I agree with the ", "http://example.com)) Terms of Use and I\'ve read the ", "http://example2.com)) Privacy"]
let mid = firstDiv[1] // http://example.com)) Terms of Use and I've read the
let link1 = mid.split(separator: ")")[0] // http://example.com
let link2 = firstDiv[2].split(separator: ")")[0] // http://example2.com

What is an easier way to replace multiple characters with other characters in a string in swift?

I am currently trying to setup a string to be added to a HTTP POST request where a user would type text and tap 'enter' and a request would be sent.
I know multiple characters (^,+,<,>) can be replaced with a single character ('_') like so:
userText.replacingOccurrences(of: "[^+<>]", with: "_"
I currently am using multiple functions of:
.replacingOccurrences(of: StringProtocol, with:StringProtocol)
like so:
let addAddress = userText.replacingOccurrences(of: " ", with: "_").replacingOccurrences(of: ".", with: "%2E").replacingOccurrences(of: "-", with: "%2D").replacingOccurrences(of: "(", with: "%28").replacingOccurrences(of: ")", with: "%29").replacingOccurrences(of: ",", with: "%2C").replacingOccurrences(of: "&", with: "%26")
Is there a more efficient way of doing this?
What you are doing is to manually encode the string with a percent encoding.
If that's the case, this will help you:
addingPercentEncoding(withAllowedCharacters:)
Returns a new string made from the receiver by replacing all characters not in the specified set with percent-encoded characters.
https://developer.apple.com/documentation/foundation/nsstring/1411946-addingpercentencoding
For your specific case this should work:
userText.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
I think the only problem you will run into with using addingPercentEncoding is that your question states that a space " " should be replaced with an underscore. Using addingPercentEncoding for a space " " will return %20. You should be able to combine some of these answers, define the remaining characters from your list that should return standard character replacement and get your desired outcome.
var userText = "This has.lots-of(symbols),&stuff"
userText = userText.replacingOccurrences(of: " ", with: "_")
let allowedCharacterSet = (CharacterSet(charactersIn: ".-(),&").inverted)
var newText = userText.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
print(newText!) // Returns This_has%2Elots%2Dof%28symbols%29%2C%26stuff
Ideally to use .urlHostAllowed CharacterSet since it works almost always.
textInput.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
But the best is combining all the possible options like here which will make sure you make it right.

Remove two characters from a string

Below is my "services" variable. I want to remove first 2 characters from it. That is I want to replace ", " with ""
let services = ", EXTERNAL SERVICE, INTERNAL SERVICE"
I want to produce following result
let services = "EXTERNAL SERVICE, INTERNAL SERVICE"
How to do it?
If you always want to remove the first two characters, use String.substring(from:).
let services = ", EXTERNAL SERVICE, INTERNAL SERVICE"
let correctServices = services.substring(from: services.index(services.startIndex, offsetBy: 2))
Output: "EXTERNAL SERVICE, INTERNAL SERVICE"
This is a solution based on the assumption that the string is composed with string concatenation from an array or loop separated by ", ".
It converts the string to array, removes the empty item(s) and converts the string back to string
let services = ", EXTERNAL SERVICE, INTERNAL SERVICE"
.components(separatedBy: ", ")
.filter{ !$0.isEmpty }
.joined(separator: ", ")
I guess the best solution is not to compose services by string concatenation before.
It looks like you want to get rid of extraneous characters from the beginning, and maybe from the end. In your case you have two characters, but there is a more general way - which is trimming. This is from a playground
// Your original string
let string = ", EXTERNAL SERVICE, INTERNAL SERVICE"
// Create a character set for things to exclude - in this case whitespace, newlines and punctuation
let charset = CharacterSet.whitespacesAndNewlines.union(.punctuationCharacters)
// Trimming removes the characters from the characterset from the beginning and the end of the string
let trimmedString = string.trimmingCharacters(in: charset) // -> "EXTERNAL SERVICE, INTERNAL SERVICE"

trimmingCharacters not working as expected when characters include hyphen Swift

Trying to understand what is going wrong in playgrounds with the next example :
let result = "+-----+".trimmingCharacters(in: CharacterSet(charactersIn: "+").inverted)
result is "+-----+"
expected result is "++"
due to method reference "Returns a new string made by removing from both ends of the String characters contained in a given character set."
Examples that work how I expect:
let result = "D123ABC".trimmingCharacters(in: CharacterSet(charactersIn: "01234567890.").inverted)
result is "123"
let result = "+-----+".trimmingCharacters(in: CharacterSet(charactersIn: "*").inverted)
result is ""
trimmingCharacters only replaces the trailing/leading characters.
If you want to replace all characters that are not "+" you can use
"+-----+".replacingOccurrences(of: "[^+]", with: "", options: .regularExpression)
Agree with rmaddy.
For more explanation check this:
let result = "123+--+abc".trimmingCharacters(in: CharacterSet(charactersIn: "+").inverted)
Result: +--+
let result = "+--+".trimmingCharacters(in: CharacterSet(charactersIn: "+").inverted)
Result: +--+

How can we remove every characters other than numbers, dot and colon in swift?

I am stuck at getting a string from html body
<html><head>
<title>Uaeexchange Mobile Application</title></head><body>
<div id='ourMessage'>
49.40:51.41:50.41
</div></body></html>
I Would like to get the string containing 49.40:51.41:50.41 . I don't want to do it by string advance or index. Can I get this string by specifying I need only numbers,dot(.) and colon(:) in swift. I mean some numbers and some special characters?
I tried
let stringArray = response.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
print("Trimmed\(newString)and count\(newString.characters.count)")
but this obviously trims away dot and colon too. any suggestions friends?
The simple answer to your question is that you need to include "." & ":" in the set that you want to keep.
let response: String = "<html><head><title>Uaeexchange Mobile Application</title></head><body><div id='ourMessage'>49.40:51.41:50.41</div></body></html>"
var s: CharacterSet = CharacterSet.decimalDigits
s.insert(charactersIn: ".:")
let stringArray: [String] = response.components(separatedBy: s.inverted)
let newString: String = stringArray.joined(separator: "")
print("Trimmed '\(newString)' and count=\(newString.characters.count)")
// "Trimmed '49.40:51.41:50.41' and count=17\n"
Without more information on what else your response might be, I can't really give a better answer, but fundamentally this is not a good solution. What if the response had been
<html><head><title>Uaeexchange Mobile Application</title></head><body>
<div id='2'>Some other stuff: like this</div>
<div id='ourMessage'>49.40:51.41:50.41</div>
</body></html>
Using a replace/remove solution to this is a hack, not an algorithm - it will work until it doesn't.
I think you should probably be looking for the <div id='ourMessage'> and reading from there to the next <, but again, we'd need more information on the specification of the format of the response.
I'd recommend to use an HTML parser, nevertheless this is a simple solution with regular expression:
let extractedString = response.replacingOccurrences(of: "[^\\d:.]+", with: "", options: .regularExpression)
Or the positive regex search which is more code but also more reliable:
let pattern = ">\\s?([\\d:.]+)\\s?<"
let regex = try! NSRegularExpression(pattern: pattern)
if let match = regex.firstMatch(in: response, range: NSMakeRange(0, response.utf8.count)) {
let range = match.rangeAt(1)
let startIndex = response.index(response.startIndex, offsetBy: range.location)
let endIndex = response.index(startIndex, offsetBy: range.length)
let extractedString = response.substring(with: startIndex..<endIndex)
print(extractedString)
}
While the simple (negative) regex search removes all characters which don't match digits, dots and colons the positive search considers also the closing (>) and opening tags (<) around the desired result so an accidental digit, dot or colon doesn't match the pattern.
You can also use the String.replacingOccurrences() method in other ways, without regex, as follows:
import Foundation
var response: String = "<html><head><title>Uaeexchange Mobile Application</title></head><body><div id='ourMessage'>49.40:51.41:50.41</div></body></html>"
let charsNotToBeTrimmed = (0...9).map{String($0)} + ["." ,":"] // you can add any character you want here, that's the advantage
for i in response.characters{
if !charsNotToBeTrimmed.contains(String(i)){
response = response.replacingOccurrences(of: String(i), with: "")
}
}
print(response)
Basically, this creates an array of characters which should not be trimmed and if a character is not out there, it gets removed in the for-loop
But you have to be warned that what you're trying to do isn't quite right...