Unable to extract substring from larger mutli-line string



I extracted some HTML code and it's stored in a string called "html".
I want to pull the number of stars from this HTML code. Looking at the
html, I thought the easiest way was to look for the word "stars" in the
html string and go from there. So I wrote this code:

Code Block
var s = "stars"
if (html.contains(s)) {
print("Found stars")
}

However, for some reason this does not work and it does not print
"Found Stars" in the bottom right part of xcode. What am I doing wrong?

Answered by OOPer in 617839022
@oofmeister27

How can I fix this?

Seems you are struggling with the same async problem.

In your code, the completion closure (from line 1 { data, response, error in till line 14 }) is executed after the communication is completed.
But your line 16 through line 25 are executed before the communication is completed.

Move everything using the result of the communication into the completion closure.

Can you tell us how stars are represented in your html?
And, can you create a concise example of html which can reproduce the same issue?
If you can, please show us the result of debugPrint(html).
Do you search for "stars" or for "*" ?
Please check one more thing.
Is html really a String? Isn't it an Array of String?
Exactly the same code compiles without errors but the result is not what you expect.
@OOper As you would probably expect, the HTML is really long so I'll just include a snippet of the HTML which contains the rating:
Code Block
</h2>
<div class="a-row a-size-small a-color-secondary"><span class="a-size-small" dir="auto">by </span><span class="a-size-small" dir="auto">John Bolton</span></div>
</div>
<div class="a-section a-spacing-none a-spacing-top-mini">
<div class="a-row a-size-small">
<span aria-label="3.1 out of 5 stars">
<i class="a-icon a-icon-star-small a-star-small-3 aok-align-bottom"><span class="a-icon-alt">3.1 out of 5 stars</span></i>
</span>


Also html is a string.

@Claude I am searching for "stars"

I tried the following in playground and it works (note the multiline """

Code Block
let html = """
</h2>
<div class="a-row a-size-small a-color-secondary"><span class="a-size-small" dir="auto">by </span><span class="a-size-small" dir="auto">John Bolton</span></div>
</div>
<div class="a-section a-spacing-none a-spacing-top-mini">
<div class="a-row a-size-small">
<span aria-label="3.1 out of 5 stars">
<i class="a-icon a-icon-star-small a-star-small-3 aok-align-bottom"><span class="a-icon-alt">3.1 out of 5 stars</span></i>
</span>
"""
var s = "stars"
if (html.contains(s)) {
print("Found stars")
}

@oofmeister27

Also html is a string. 

Thanks for clarifying.

I have found your thread in SO, and you have shown some partial code there.
It uses URLSession, and I guess you have fallen into some async problem.

Please show full code.
@OOPer I got a part solution here:
Code Block swift
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else {
print(error ?? "")
return
}
html = String(data: data, encoding: .utf8)!
let pattern = #"(\d.\d) out of 5 stars"#
if let range = html.range(of: pattern, options: .regularExpression) {
let rating = html[range].prefix(3)
ocrText = ocrText + rating
print("testing", ocrText) //prints with rating
}
}.resume()
print("LATER:", ocrText) //doesn't print with rating
DispatchQueue.main.async {
self.ocrTextView.text = ocrText
self.scanButton.isEnabled = true
}

It is correctly getting the number of stars, but the problem is that I have a text view (as you can see in the above code) which I set equal to the string ocrText. However, I put two print statements: one inside the URLSession method and one outside the URLSessionMethod. I am trying to get the rating into the string ocrText, which works in the print statement in the URLSession method but not outside this method. How can I fix this?

BTW all the above code is in a seprate function and then I call this function in the viewDidLoad method.

edit: do you want the full code in the viewcontroller.swift ? its pretty long and i think there's a character limit for a post

Accepted Answer
@oofmeister27

How can I fix this?

Seems you are struggling with the same async problem.

In your code, the completion closure (from line 1 { data, response, error in till line 14 }) is executed after the communication is completed.
But your line 16 through line 25 are executed before the communication is completed.

Move everything using the result of the communication into the completion closure.

Just to make sure I am understanding you: You are saying to move the DispatchQue.main.async method into the URLSession method?
Thanks so much, moving it worked.
@OOper not sure if you have some experience with ARKit, but now I am trying to take the rating and display it on the user's camera. I know how to display simple text on the user's screen, but for some reason I'm getting an error when running this code:

Code Block swift
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
configure()
configureOCR()
let text = SCNText(string: ocrTextView, extrusionDepth: 2)
let material = SCNMaterial()
material.diffuse.contents = UIColor.magenta
text.materials = [material]
let node = SCNNode()
node.position = SCNVector3(x:0, y:0.02, z:-0.1)
node.scale = SCNVector3(x:0.01, y:0.01, z:0.01)
node.geometry = text
sceneView.scene.rootNode.addChildNode(node)
sceneView.autoenablesDefaultLighting = true
}


When I run it, it crashes and gives an exception: Thread 1: Exception: "-[UITextInputTraits length]: unrecognized selector sent to instance 0x1035332b0"



@OOPer i have 4 different view controllers so I can attach the project if that's needed.
@oofmeister27

not sure if you have some experience with ARKit

In fact, I'm quite an amateur.

You should better start a new thread for this issue. Please do not forget to add an appropriate tag, so that experts can find and watch the thread.

Alright no problem I will ask in a new thread. Thanks for all your help!
Unable to extract substring from larger mutli-line string
 
 
Q