Home > Net >  How find integer in text
How find integer in text

Time:08-21

Help me figure out how to work with text

i have a string like: "word1 number: word2" for example : "result 0: Good" or "result 299: Bad"

i need print Undefined/Low or High

When string is null , print Undefined

When number 0-15, print Low

When number >15, print High

type GetResponse = 
{ 
  MyData: string voption
  ErrorMessage: string voption }

val result: Result<GetResponse, MyError>

and then i try:

MyData =
match result with
| Ok value ->
    if (value.Messages = null) then
        ValueSome "result: Undefined"
    else
        let result =
            value.Messages.FirstOrDefault(
                (fun x -> x.ToUpperInvariant().Contains("result")),
                "Undefined"
            )

        if (result <> "Undefined") then
            ValueSome result
        else
            errors.Add("We don't have any result")
            ValueNone
| Error err ->
    errors.Add(err.ToErrorString)
    ValueNone
ErrorMessage =
  if errors.Any() then
   (errors |> String.concat ", " |> ValueSome)
  else
   ValueNone

but i dont know gow check in string number and maybe there is some way print this without a billion if?

CodePudding user response:

Parsing gets complex very quickly. I recommend using FParsec to simplify the logic and avoid errors. A basic parser that seems to meet your needs:

open System
open FParsec

let parseWord =
    manySatisfy Char.IsLetter

let parseValue =
    parseWord              // parse any word (e.g. "result")
        >>. spaces1        // skip whitespace
        >>. puint32        // parse an unsigned integer value
        .>> skipChar ':'   // skip colon character
        .>> spaces         // skip whitespace
        .>> parseWord      // parse any word (e.g. "Good")

You can then use it like this:

type ParserResult = Undefined | Low | High

let parse str =
    if isNull str then Result.Ok Undefined
    else
        match run parseValue str with
            | Success (num, _ , _) ->
                if num <= 15u then Result.Ok Low
                else Result.Ok High
            | Failure (errorMsg, _, _) ->
                Result.Error errorMsg

parse null |> printfn "%A"                // Ok Undefined
parse "result 0: Good" |> printfn "%A"    // Ok Low
parse "result 299: Bad" |> printfn "%A"   // Ok High
parse "invalid input" |> printfn "%A"     // Error "Error in Ln: 1 Col: 9 ... Expecting: integer number"

There's definitely a learning curve with FParsec, but I think it's worth adding to your toolbelt.

CodePudding user response:

I agree with Brian that parsing can become quite tricky very quickly. However if you have some well established format of the input and you're not very much into writing complex parsers, good old regular expressions can be of service ;)

Here is my take on the problem - please note that it has plenty of room to improve, this is just a proof of concept:

open System.Text.RegularExpressions

let test1 = "result 0: Good"
let test2 = "result 299: Bad"
let test3 = "some other text"

type ParserResult = 
    | Undefined 
    | Low of int 
    | High of int


let (|ValidNumber|_|) s = 
    //https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=net-6.0
    let rx = new Regex("(\w\s )(\d )\:(\s \w)") 
    let matches = rx.Matches(s)
    if matches.Count > 0 then
        let groups = matches.[0].Groups |> Seq.toList
        match groups with
        | [_; _; a; _] -> Some (int a.Value)
        | _ -> None
    else
        None

let parseMyString str = 
    match str with
    | ValidNumber n when n < 16 -> Low n
    | ValidNumber n -> High n
    | _ -> Undefined

//let r = parseMyString test1
printfn "%A" (parseMyString test1)
printfn "%A" (parseMyString test2)
printfn "%A" (parseMyString test3)

The active pattern ValidNumber returns the Some number if a match of the input string is found, otherwise it returns None. The parseMyString function uses the pattern and guards to initialise the final ParserOutput value.

  • Related