I am trying to extract a href from a text and let it clickable to the website.
This is how my try looks like but it does not work correctly:
extension String {
func findHref() -> [String] {
var arr_hasStrings:[String] = []
let regex = try? NSRegularExpression(pattern: "https[a-zA-Z0-9_\\p{Arabic}\\p{N}]*\\.com)", options: [])
if let matches = regex?.matches(in: self, options:[], range:NSMakeRange(0, self.count)) {
for match in matches {
arr_hasStrings.append(NSString(string: self).substring(with: NSRange(location:match.range.location, length: match.range.length )))
}
}
return arr_hasStrings
}
}
and then I used it like this:
struct Details: View {
var body: some View {
VStack {
ForEach( typedcomment.findHashtags(), id: \.self ){
element in
HStack{
Text(element).background(Color("bg"))
}
}
}
}
}
It worked for https://stackoverflow.com
but not for a link like this: https://www.apple.com/de/macbook-pro-13/
try this:
let input = "This is a test with the URL https://www.apple.com/de/macbook-pro-13/ to be detected."
func returnUrl(text: String) -> URL? {
let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let matches = detector.matches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count))
var url: URL?
for match in matches {
guard let range = Range(match.range, in: input) else { continue }
let urlFound = input[range]
url = URL(string: String(urlFound))
}
return url
}
from https://www.hackingwithswift.com/example-code/strings/how-to-detect-a-url-in-a-string-using-nsdatadetector
Suppose I have a html link like this:
https://mitsui-shopping-park.com/lalaport / koshien /
I want to extract:
NOT THIS LINK
I tried: someString.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil) but that gives me:
BUT THIS LINK
Please help.
No need for a regular expression, you could use the link property of an attributed string.
First, let's use this extension:
extension String{
func convert2Html() -> NSAttributedString {
guard let data = data(using: .utf8) else { return NSAttributedString() }
do {
let htmlAttrib = NSAttributedString.DocumentType.html
return try NSAttributedString(data: data,
options: [.documentType : htmlAttrib],
documentAttributes: nil)
} catch {
return NSAttributedString()
}
}
}
to convert this String:
let html = " https://mitsui-shopping-park.com/lalaport / koshien / "
to an NSAttributedString:
let attrib = html.convert2Html()
And then extract the link this way :
let link = attrib.attribute(.link, at: 0, effectiveRange: nil)
if let url = link as? NSURL, let href = url.absoluteString {
print(href) //https://mitsui-shopping-park.com/lalaport/koshien/
}
Here's one possible solution to grab the value between the href=" and the closing ". This only works with one href in the string.
let html = " https://mitsui-shopping-park.com/lalaport / koshien / "
if let hrefRange = html.range(of: "(?:href\\s*=\\s*\")[^\"]*(?:\")", options: .regularExpression) {
let href = html[hrefRange]
print(href)
} else {
print("There is no href")
}
Let's break down that regular expression:
First, let's remove the extra \ needed in the RE to make it a value Swift string. This leaves us with:
(?:href\s*=\s*")[^"]*(?:")
This has three main parts:
(?:href\s*=\s*") - the href, optional space, =, optional space, and opening quote
[^"]* - the actual URL - everything that isn't a quote
(?:") - the close quote
The (?: ) syntax means that the stuff inside won't be part of the returned string.
Use NSRegularExpression.matches for the capture group feature of Regular Expression. I always use this handy extension method:
extension String {
func capturedGroups(withRegex pattern: String) -> [String?] {
var results = [String?]()
var regex: NSRegularExpression
do {
regex = try NSRegularExpression(pattern: pattern, options: [])
} catch {
return results
}
let matches = regex.matches(in: self, options: [], range: NSRange(location:0, length: self.count))
guard let match = matches.first else { return results }
let lastRangeIndex = match.numberOfRanges - 1
guard lastRangeIndex >= 1 else { return results }
for i in 0...lastRangeIndex {
let capturedGroupIndex = match.range(at: i)
if(capturedGroupIndex.length>0)
{
let matchedString = (self as NSString).substring(with: capturedGroupIndex)
results.append(matchedString)
}
else
{
results.append(nil)
}
}
return results
}
}
var html = """
https://mitsui-shopping-park.com/lalaport / koshien /
"""
print(html.capturedGroups(withRegex: "href\\s*=\\s*\"([^\"]+)\"")[1])
How do I extract hashtag strings from a text in Swift? I've seen some answers but they seem too complicated for what I need and I don't really understand how RegEx works?
E.g.
Text: "This is #something with a lot of #random #hashtags #123yay."
What I want: "something", "random", "hashtags", "123yay".
Thanks!
here is the helper method to convert your string into hash detection string
this extension find the # words from sting also including arabic words.
extension String {
func findMentionText() -> [String] {
var arr_hasStrings:[String] = []
let regex = try? NSRegularExpression(pattern: "(#[a-zA-Z0-9_\\p{Arabic}\\p{N}]*)", options: [])
if let matches = regex?.matches(in: self, options:[], range:NSMakeRange(0, self.count)) {
for match in matches {
arr_hasStrings.append(NSString(string: self).substring(with: NSRange(location:match.range.location, length: match.range.length )))
}
}
return arr_hasStrings
}
}
And below method converts your string into Reach colorful hash string.
func convert(_ hashElements:[String], string: String) -> NSAttributedString {
let hasAttribute = [NSAttributedStringKey.foregroundColor: UIColor.orange]
let normalAttribute = [NSAttributedStringKey.foregroundColor: UIColor.black]
let mainAttributedString = NSMutableAttributedString(string: string, attributes: normalAttribute)
let txtViewReviewText = string as NSString
hashElements.forEach { if string.contains($0) {
mainAttributedString.addAttributes(hasAttribute, range: txtViewReviewText.range(of: $0))
}
}
return mainAttributedString
}
i.e
let text = "#Jaydeep #Viral you have to come for party"
let hashString = convert(text.findMentionText(), string: text)
Output:
extension String
{
func hashtags() -> [String]
{
if let regex = try? NSRegularExpression(pattern: "#[a-z0-9]+", options: .caseInsensitive)
{
let string = self as NSString
return regex.matches(in: self, options: [], range: NSRange(location: 0, length: string.length)).map {
string.substring(with: $0.range).replacingOccurrences(of: "#", with: "").lowercased()
}
}
return []
}
}
then, to get the hashtags array
yourstring.hashtags()
Here is the source
let str = "This is #something with a lot of #random #hashtags #123yay."
let words = str.components(separatedBy: " ")
var hashTags = [String]()
for word in words{
if word.hasPrefix("#"){
let hashtag = word.dropFirst()
hashTags.append(String(hashtag))
}
}
print("Hashtags :: ", hashTags)
First things first, this works best in a TextView. So set one up inside of your view however you want, but make sure that your ViewController has a UITextViewDelegate & the textView is delegated to that view controller.
I’m also doing this with some prefilled information, but the same concept applies with pulling data from your database and what not.
This is how we set up our ViewController:
class ViewController: UIViewController, UITextViewDelegate {
var string = "Hello, my name is #Jared & #Jared and I like to move it."
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.text = string
textView.delegate = self
}
The overall task we’re trying to accomplish in this part is just to split up all the words in our textView. It’s simpler than you might think:
First, let’s create our extension:
Now add this to your ViewController:
extension UITextView {
func resolveTags(){
let nsText:NSString = self.text as NSString
let words:[String] = nsText.components(separatedBy: " ")
let attrs = [
NSAttributedStringKey.font : UIFont.init(name: "HelveticaNeue", size: 13),
NSAttributedStringKey.foregroundColor : UIColor.black
]
let attrString = NSMutableAttributedString(string: nsText as String, attributes:attrs)
for word in words {
if word.hasPrefix("#") {
let matchRange:NSRange = nsText.range(of: word as String)
var stringifiedWord:String = word as String
stringifiedWord = String(stringifiedWord.dropFirst())
attrString.addAttribute(NSAttributedStringKey.link, value: "hash:\(stringifiedWord)", range: matchRange)
attrString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.blue , range: matchRange)
}
}
self.attributedText = attrString
}
}
Let’s use this thing!
It all comes down to this. We have this function working, now how do we use it?
Easy.
Inside of your viewDidLoad function, or wherever you set your textView text, just call:
textView.resolveTags()
Result:
Courtesy of: Jared Davidson On Twitter
You can also use third party Activelabel . this is simple to use and also support Hashtags (#), Mentions (#), URLs (http://) and custom regex patterns
https://github.com/optonaut/ActiveLabel.swift
I just changed #JayDeep 's answer to more swifty style.
extension String {
var tags: [String] {
let regex = try? NSRegularExpression(pattern: "(#[a-zA-Z0-9_\\p{Arabic}\\p{N}]*)", options: [])
let nsRange: NSRange = .init(location: 0, length: self.count)
guard let matches = regex?.matches(in: self, options: NSRegularExpression.MatchingOptions(), range: nsRange)
else { return [] }
return matches
.map { match in
let startIndex = self.index(self.startIndex, offsetBy: match.range.location)
let endIndex = self.index(startIndex, offsetBy: match.range.length)
let range = startIndex ..< endIndex
return String(self[range])
}
}
}
My clean solution: We will return PrefixesDetected to the view. And the view will format it as he wants. (So we will execute yourString.resolvePrefixes()) in the viewModel and we will be able to test it.
struct PrefixesDetected {
let text: String
let prefix: String?
}
extension String {
func resolvePrefixes(_ prefixes: [String] = ["#", "#"]) -> [PrefixesDetected] {
let words = self.components(separatedBy: " ")
return words.map { word -> PrefixesDetected in
PrefixesDetected(text: word,
prefix: word.hasPrefix(prefixes: prefixes))
}
}
func hasPrefix(prefixes: [String]) -> String? {
for prefix in prefixes {
if hasPrefix(prefix) {
return prefix
}
}
return nil
}
}
Then in the view we can format it as for example: (In this case we want both in the same color but in this way you can give them different behaviors)
Here I do with reduce but this is just to show an example, you can format it as you want! :)
titleDetectedPrefixes.reduce(NSAttributedString(), { result, prefixDectedWord in
let wordColor: UIColor = prefixDectedWord.prefix != nil ? .highlightTextMain : .mainText
let attributedWord = NSAttributedString(string: prefixDectedWord.text)
{ Add desired attributes }
})
for those who are using swiftUI you can achieve it by using the "+" operator
so the final solution will look like this
static func tagHighlighter(description : String , previousText : Text = Text("") , tag : String = "#") -> Text {
var t : Text = Text("")
let words : [String] = description.components(separatedBy: " ")
for word in words {
if !word.isEmpty {
let tag = word[word.startIndex]
if tag == "#" {
t = t + Text("\(word) ").foregroundColor(Color("tag_color"))
} else if tag == "#" {
t = t + Text("\(word) ").foregroundColor(Color("tag_color"))
} else {
t = t + Text("\(word) ")
}
}
}
return t
}
This is how I'm doing it
private func getHashTags(from caption: String) -> [String] {
var words: [String] = []
let texts = caption.components(separatedBy: " ")
for text in texts.filter({ $0.hasPrefix("#") }) {
if text.count > 1 {
let subString = String(text.suffix(text.count - 1))
words.append(subString.lowercased())
}
}
return words
}
Copy paste this extension to your class:
extension UITextView{
func insertTextWithHashtags(text textString: String){
let nsTextString: NSString = textString as NSString
let simpleTextAttributes: [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor : UIColor(named: "Black Color")!, NSAttributedString.Key.font : UIFont(name: "Inter-Regular", size: 16.0)!]
let attributedString = NSMutableAttributedString(string: textString, attributes: simpleTextAttributes)
var word = ""
for text in textString+" "{ //+" " is for loop to run one extra time to complete hashtag
if text == "#" || text == "\n" || text == " "{
if word.hasPrefix("#"){
let range = nsTextString.range(of: word)
let link = [NSAttributedString.Key.link : word]
attributedString.addAttributes(link, range: range)
if text == "#"{
word = "#"
}else{
word = ""
}
}else{
if text == "#"{
word = "#"
}
}
}else{
if word.hasPrefix("#"){
word.append(text)
}
}
}
//For for applying attributes to hashtag
let linkAttributes: [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor : UIColor(named: "Primary Color")!]
self.linkTextAttributes = linkAttributes
self.attributedText = attributedString
}
}
and then call it like this:
postTextView.insertTextWithHashtags(text: "#Hello#Hey #Space")
I'm accessing the HTML of a webpage after the user has submitted information.
If I have...
var htmlString = "This is the massive HTML string - it has lots of characters "FindStringDetails"<123789456.123456> This is a massive HTML string - "
var findString = "FindStringDetails\"<"
Is there a suitable way that I could extract the numbers that come after "FindStringDetails"< to give me 123789456.123456 ?
import Foundation
var htmlString = "This is the massive HTML string - it has lots of characters \"FindStringDetails\"<123789456.123456> This is a massive HTML string - "
var findString = "FindStringDetails\"<"
extension String {
func matchingStrings(regex: String) -> [[String]] {
guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
let nsString = NSString(string: self)
let results = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
return results.map { result in
(0..<result.numberOfRanges).map { result.range(at: $0).location != NSNotFound
? nsString.substring(with: result.range(at: $0))
: ""
}
}
}
}
let m = htmlString.matchingStrings(regex: "\(findString)(\\d+)\\.(\\d+)")
print(m[0][1]) // 123789456
print(m[0][2]) // 123456
(Code adapted from here.)
how to use random string to let or var to url link
i want to make random string for url
let url = URL(string:"https://www.pallive.net/random.json")
or see the code when i change values in the site linke in the app do not changed,but if i chnage name of url it change
the code not reload if i change the value in json and keep same file
if i want to reload i have to change the name of file how to do some thange
auotmatic change the url and keep the orginal in the ftp server
import Foundation
class Episode
{
var title: String?
var description: String?
var thumbnailURL: URL?
var url: URL?
var episodes = [Episode]()
init(title: String, description: String, thumbnailURL: URL, createdAt: String, author: String)
{
self.title = title
self.description = description
self.thumbnailURL = thumbnailURL
}
init(espDictionary: [String : AnyObject])
{
self.title = espDictionary["title"] as? String
// description = espDictionary["description"] as? String
thumbnailURL = URL(string: espDictionary["thumbnailURL"] as! String)
self.url = URL(string: espDictionary["link"] as! String)
}
static func downloadAllEpisodes(completion: #escaping ([Episode]) -> ()) {
var episodes = [Episode]()
let url = URL(string:"https://www.pallive.net/random.json")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error)
completion(episodes)
}
else {
if let jsonData = data ,let jsonDictionary = NetworkService.parseJSONFromData(jsonData) {
let espDictionaries = jsonDictionary["episodes"] as! [[String : AnyObject]]
for espDictionary in espDictionaries {
let newEpisode = Episode(espDictionary: espDictionary)
episodes.append(newEpisode)
}
}
completion(episodes)
DispatchQueue.main.async(execute: {
completion(episodes)
})
}
}.resume()
}
func randomString(_ length: Int) -> String {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let len = UInt32(letters.length)
var randomString = ""
for _ in 0 ..< length {
let rand = arc4random_uniform(len)
var nextChar = letters.character(at: Int(rand))
randomString += NSString(characters: &nextChar, length: 1) as String
}
return randomString
}
}