如何解析文本并提取整数
How to parse Text and extract integer
我有这个Data.Text
"Check: Find max among: 70, 102, 271, 40"
如何从此文本中提取数字并对其应用函数?
对于 String
你可以使用:
maximum . map (read) . filter (all isDigit) . map (filter ((/=) ',')) words
或者对于 Text
,使用:
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
然后您可以编写一个 main
函数来读取 stdin
的值。
main :: IO ()
main = do
x <- getLine
putStrLn $ show $ fString (pack x) --to demonstrate that it works with Data.Text
此代码示例展示了一种简单的方法:
import Data.List
import Control.Monad
getLine >>= \line -> putStrLn $ show $ maximum $ (map read . words $ filter (/=',') $ line :: [Int])
您可以使用许多 Haskell 解析库来解析 Text
类型,但对于这样一个简单的示例,我只是将其分解为单词、过滤数字并进行转换。正如 dfeuer 指出的那样,其他答案使用的 Haskell 的 String
类型与您可能错误暗示的 Text
类型之间存在很大差异。对于文本类型,操作看起来非常相似,但您没有 Prelude read
操作:
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
出于各种美学原因,我喜欢这种方法:
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
这是适用于 Text
的单行解决方案。它将 Text
中的数字提取到列表中
sepCap
combinator, and then you could apply the maximum
函数。
由于这是一个解析器,您可以将其扩展到比本示例更复杂的内容,例如实际解析字符串第一部分中的查询指令。
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
我有这个Data.Text
"Check: Find max among: 70, 102, 271, 40"
如何从此文本中提取数字并对其应用函数?
对于 String
你可以使用:
maximum . map (read) . filter (all isDigit) . map (filter ((/=) ',')) words
或者对于 Text
,使用:
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
然后您可以编写一个 main
函数来读取 stdin
的值。
main :: IO ()
main = do
x <- getLine
putStrLn $ show $ fString (pack x) --to demonstrate that it works with Data.Text
此代码示例展示了一种简单的方法:
import Data.List
import Control.Monad
getLine >>= \line -> putStrLn $ show $ maximum $ (map read . words $ filter (/=',') $ line :: [Int])
您可以使用许多 Haskell 解析库来解析 Text
类型,但对于这样一个简单的示例,我只是将其分解为单词、过滤数字并进行转换。正如 dfeuer 指出的那样,其他答案使用的 Haskell 的 String
类型与您可能错误暗示的 Text
类型之间存在很大差异。对于文本类型,操作看起来非常相似,但您没有 Prelude read
操作:
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
出于各种美学原因,我喜欢这种方法:
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
这是适用于 Text
的单行解决方案。它将 Text
中的数字提取到列表中
sepCap
combinator, and then you could apply the maximum
函数。
由于这是一个解析器,您可以将其扩展到比本示例更复杂的内容,例如实际解析字符串第一部分中的查询指令。
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