Reputation: 99
I have this Data.Text
"Check: Find max among: 70, 102, 271, 40"
How do I extract the numbers from this text and apply a function to them?
Upvotes: 3
Views: 1285
Reputation: 3426
Here's a one-line solution that works on Text
. It pulls numbers out of the Text
into a list with the
sepCap
combinator, and then you could apply the maximum
function.
And since this is a parser, you can extend it to something more complicated than this example, like actually parsing the query instructions out of the first part of the string.
import Replace.Megaparsec
import Text.Megaparsec
import Text.Megaparsec.Char.Lexer
import Data.Either
import Data.Maybe
import qualified Data.Text as T
maximum $ rights $ fromJust $ parseMaybe (sepCap (decimal :: Parsec Void T.Text Int))
"Check: Find max among: 70, 102, 271, 40"
271
Upvotes: 0
Reputation: 477607
For a String
you can use:
maximum . map (read) . filter (all isDigit) . map (filter ((/=) ',')) words
Or for a Text
, use:
import Prelude as P
import Data.Text as T
fString :: Text -> Integer
fString = maximum . P.map (read) . P.filter (all isDigit) . P.map (P.filter ((/=) ',')) . P.map (T.unpack) . T.words
You can then for instance write a main
function to read the value from stdin
.
main :: IO ()
main = do
x <- getLine
putStrLn $ show $ fString (pack x) --to demonstrate that it works with Data.Text
Upvotes: -2
Reputation: 40438
This code example shows a simple way to do it:
import Data.List
import Control.Monad
getLine >>= \line -> putStrLn $ show $ maximum $ (map read . words $ filter (/=',') $ line :: [Int])
Upvotes: 0
Reputation: 52057
For various esthetic reasons I like this approach:
import qualified Data.Text as T
import Data.Text.Read
import Data.Either
import Data.Char
import Data.Text.IO as T
readNums :: T.Text -> [Int]
readNums =
map fst . -- 5. extract the parsed numbers
snd . partitionEithers . -- 4. collect only the valid numbers
map decimal . -- 3. parse each substring as an number
filter (not . T.null) . -- 2. filter out empty strings (not necessary)
T.split (not . isDigit) -- 1. split on non-digits
Upvotes: 2
Reputation: 64750
You can use many of the Haskell parsing libraries to parse Text
types but for such a simple example I'd just break it into words, filter for the digits and convert. As dfeuer is pointing out, there is a big difference between Haskell's String
type which the other answers use and the Text
type which you perhaps mistakenly implied. For the text type the operations look quite similar but you don't have the Prelude read
operation:
import qualified Data.Text as T
import Data.Text (Text)
import Data.Char (isDigit)
import Data.Text.Read
myRead :: Text -> [Int]
myRead = map num -- Convert the remaining elements into Ints
. filter (not . T.null) -- Drop all empty words
. map (T.filter isDigit) -- Drop all non-digits in each word (including signs!)
. T.words -- Chop the string into words
num :: Text -> Int
num = either (error . show) fst -- Throw an exception if it wasn't a signed decimal
. signed decimal -- Read a signed decimal
Upvotes: 1