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.