如何解析文本并提取整数

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