Home > Enterprise >  How to extract all numbers from a string in Haskell?
How to extract all numbers from a string in Haskell?

Time:12-06

So basically, let's say I have a String = "W2932,B23829,/,,,W29".

How do I extract all numbers so that I have a list = [2932, 23829, 29].

Sadly haven't found any solution on SO or google. I thought about checking each Char of the String to be a digit and then adding them but only can produce a list of all digits individually.

CodePudding user response:

https://hackage.haskell.org/package/replace-megaparsec

import Replace.Megaparsec (splitCap)
import Text.Megaparsec.Char.Lexer (decimal)
import Data.Either (rights)

rights $ splitCap decimal "W2932,B23829,/,,,W29"
[2932,23829,29]

CodePudding user response:

I came across this while solving Advent of Code 2022 day 5. Strings are in the format "move 1 from 2 to 12" and I need to get [1, 2, 12]. It's the same as OP's problem and I wanted to solve it without packages. OP's attempt/idea is basically this, which, as noted, doesn't collect multi-digit runs into multi-digit numbers.

The solution I took was to throw away any leading non-digit chunks, slurp the next digit chunk and repeat recursively on the tail after those two actions, gluing the found number to the front of the recursively-produced sublist.

import Data.Char (isDigit)

nonDigit :: Char -> Bool
nonDigit = not . isDigit

extractNumbers :: String -> [Int]
extractNumbers [] = []
extractNumbers xs = do
    let afterDroppingNonDigits = dropWhile nonDigit xs
    let num = takeWhile isDigit afterDroppingNonDigits
    let afterDroppingNumber = dropWhile isDigit afterDroppingNonDigits
    if num == [] then []
    else [read num :: Int]    extractNumbers afterDroppingNumber

main :: IO ()
main = do
    print $ extractNumbers "W2932,B23829,/,,,W29" -- [2932,23829,29]
    print $ extractNumbers "22,33,44" -- [22,33,44]
    print $ extractNumbers "22,33,44 " -- [22,33,44]
    print $ extractNumbers " " -- []
    print $ extractNumbers "" -- []

I'm coming from an imperative background and Haskelling recreationally, so I'm sure there is a more elegant way to do this. Feel free to leave suggestions for improvement.

  • Related