Now I look for a replacement of the function to parse securityStatusPercent
.
Here is the function found in the linked session archive, that does not work because of the regex problem:
getSecurityStatusPercentFromUINodeText : String -> Maybe Int
getSecurityStatusPercentFromUINodeText text =
"(?<=='Security status'>)\\s*(|-)\\d+(|\\.\\d+)\\s*(?=\\<)"
|> Regex.fromString
|> Maybe.andThen (\regex -> text |> Regex.find regex |> List.head)
|> Maybe.andThen (.match >> String.trim >> String.replace "," "." >> String.toFloat)
|> Maybe.map ((*) 100 >> round)
Here is a part of the string that we got from the game client UI, in that session:
<hint='Security status'>0.9</hint></color><fontsize=12><fontsize=8> </fontsize><<fontsize=8>
I removed the beginning and the end to make it easier to read. What is important is that we have additional text before and after the part that we want to extract.
In this scenario, the part of the string we want to extract is “0.9”. That should be parsed to a securityStatusPercent
of 90
In other words, we are looking for a function that returns the substring “0.9” out of the larger string above. To transform the string "0.9"
to the number 90
, we can continue to use String.toFloat
, multiply by 100
and round
as before.
The function String.split
can help us remove the parts before and after the substring of interest.
We can start by removing the part before the number: To do this, I use the substring with the preceding XML tag as the argument for String.split
. I use the Elm repl to check this approach works:
> String.split "<hint='Security status'>" "<hint='Security status'>0.9</hint></color><fontsize=12><fontsize=8>"
["","0.9</hint></color><fontsize=12><fontsize=8>"]
: List String
In the output from the REPL, we see that this expression resulted in a List String
with two elements. The second element in this list is the substring after the first occurrence of "<hint='Security status'>"
, so it starts with the number we want to get out eventually.
We can use List.drop 1
and List.head
to get the second element from this list:
> String.split "<hint='Security status'>" "<hint='Security status'>0.9</hint></color><fontsize=12><fontsize=8>" |> List.drop 1 |> List.head
Just "0.9</hint></color><fontsize=12><fontsize=8>"
: Maybe String
The next step is to remove the substring after the number that we don’t need.
In the concrete String from the linked scenario, I see the first non-whitespace character after the number is "<"
. So I use this to separate the number from the rest:
> String.split "<hint='Security status'>" "<hint='Security status'>0.9</hint></color><fontsize=12><fontsize=8>" |> List.drop 1 |> List.head |>
| Maybe.andThen (String.split "<" >> List.head)
|
Just "0.9" : Maybe String
To get the number, I add String.toFloat
and the rounding as we already used it in the earlier implementation:
> String.split "<hint='Security status'>" "<hint='Security status'>0.9</hint></color><fontsize=12><fontsize=8>" |> List.drop 1 |> List.head |>
| Maybe.andThen (String.split "<" >> List.head) |> Maybe.andThen (String.trim >> String.toFloat) |> Maybe.map ((*) 100 >> round)
|
Just 90 : Maybe Int
To prepare this for integration in the app-code, I translate this expression into a function:
> getSecurityStatusPercentFromUINodeText = String.split "<hint='Security status'>" >> List.drop 1 >> List.head >> Maybe.andThen (String.split "<" >> List.head) >> Maybe.andThen (String.trim >> String.toFloat) >> Maybe.map ((*) 100 >> round)
<function> : String -> Maybe Int
Now I can test this function by applying a string:
> getSecurityStatusPercentFromUINodeText "spdpfijj <hint='Security status'> 0.54 <somethingelse"
Just 54 : Maybe Int
So we have the new function to parse the security level percentage:
getSecurityStatusPercentFromUINodeText : String -> Maybe Int
getSecurityStatusPercentFromUINodeText =
String.replace " " ""
>> String.toLower
>> String.split "<hint='securitystatus'>"
>> List.drop 1
>> List.head
>> Maybe.andThen (String.split "<" >> List.head)
>> Maybe.andThen (String.trim >> String.toFloat)
>> Maybe.map ((*) 100 >> round)
To make our new function more robust against possible future changes, I added some more processing steps at the beginning:
- Removing space characters.
- Mapping to lowercase characters.
As a result of these additional preprocessing steps, I needed to change the argument to String.split
to "<hint='securitystatus'>"
After replacing the function in the app code, we can run a simulation with the session archive to confirm we get the right output overall:
In the status text from the app in the simulation we can see the “90” appearing where the older app displayed no securityStatusPercent
. That looks like a complete fix.