【问题标题】:rearranging string containing repeating patterns of variable length重新排列包含可变长度重复模式的字符串
【发布时间】:2010-08-03 03:08:06
【问题描述】:

我有一个布局如下的文件:

表名_of_table

COLUMNS first_column 2nd_column [..] n-th_column

VALUES 1st_value 2nd_value [...] 第 n 个值

VALUES yet_another_value ...继续

ANOTHER TABLE 从头开始​​重复.....

我想为我重新排列这个文本文件,所以我不必在每个 VALUES 行前面输入 TABLE 和 COLUMNS,从而产生:

TABLE name_of_table COLUMNS first_column [..] n-th column VALUES 1st_value

TABLE name_of_table COLUMNS first_column [..] n-th column VALUES yetanother_value

我需要在这里一次输入并重新排列几行,因此使用 hGetContents 将整个文本文件作为字符串获取似乎是合适的,产生如下字符串:

TABLE name_of_table COLUMNS first_column [..] n-th_column VALUES 1st_value [..] n-th_value VALUES another_value [..] yet_another VALUES ...... ANOTHER TABLE .... COLUMNS .... VALUES [ ....]价值观 ...

我已经尝试使用嵌套的 case of's 和递归来做到这一点。这给了我一个需要帮助的困境:

1) 我需要递归以避免无休止的大小写嵌套问题。

2) 使用递归,我不能替代添加字符串的前面部分,因为递归只引用字符串的尾部!

说明问题:

myStr::[[Char]]->[[Char]] myStr [] = [] myStr one = case (head one) of "table" -> "insert into":(head two):columnRecursion (three) ++ case (head four) of "values" -> (head four):valueRecursion (tail three) ++ myStr (tail four) _ -> case head (tail four) of "values" -> (head (tail four):myStr (tail (tail four)) _ -> where two = tail one three = tail two four = tail three columnRecursion::[[Char]] -> [[Char]] columnRecursion [] = [] columnRecursion cool = case (head cool) of "columns" -> "(":columnRecursion (tail cool) "values" -> [")"] _ -> (head cool):columnRecursion (tail cool) valueRecursion::[[Char]] -> [[Char]] valueRecursion foo = case head foo of "values" -> "insert into":(head two):columnRecursion (three) ++ valueRecursion (tail foo) "table" -> [] "columns"-> [] _ -> (head foo):valueRecursion (tail foo)

我以 FIRSTPART, VALUES bla bla VALUES bla bla 结束,但我无法再次获取 FIRSTPART 来创建 FIRSTPART, VALUES, FIRSTPART, VALUES, FIRSTPART, VALUES。

试图通过在 valueRecursion 中引用 myStr 来做到这一点显然超出了范围。

怎么办??

【问题讨论】:

  • 似乎您需要采取两管齐下的方法——将输入解析为合理的数据结构,然后遍历数据结构以生成经过处理的输出。我会看看我是否找到了一个优雅的解决方案。

标签: parsing list haskell


【解决方案1】:

对我来说,这种问题刚刚超过使用真实解析工具的阈值。这是Attoparsec 的快速工作示例:

import Control.Applicative
import Data.Attoparsec (maybeResult)
import Data.Attoparsec.Char8
import qualified Data.Attoparsec.Char8 as A (takeWhile)
import qualified Data.ByteString.Char8 as B
import Data.Maybe (fromMaybe)

data Entry = Entry String [String] [[String]] deriving (Show)

entry = Entry <$> table <*> cols <*> many1 vals
items = sepBy1 (A.takeWhile $ notInClass " \n") $ char ' '
table = string (B.pack "TABLE ") *> many1 (notChar '\n') <* endOfLine
cols = string (B.pack "COLUMNS ") *> (map B.unpack <$> items) <* endOfLine
vals = string (B.pack "VALUES ")  *> (map B.unpack <$> items) <* endOfLine

parseEntries :: B.ByteString -> Maybe [Entry]
parseEntries = maybeResult . flip feed B.empty . parse (sepBy1 entry skipSpace)

还有一点机械:

pretty :: Entry -> String
pretty (Entry t cs vs)
  = unwords $ ["TABLE", t, "COLUMNS"]
  ++ cs ++ concatMap ("VALUES" :) vs

layout :: B.ByteString -> Maybe String
layout = (unlines . map pretty <$>) . parseEntries

testLayout :: FilePath -> IO ()
testLayout f = putStr . fromMaybe [] =<< layout <$> B.readFile f

给定这个输入:

TABLE test
COLUMNS a b c
VALUES 1 2 3
VALUES 4 5 6

TABLE another
COLUMNS x y z q
VALUES 7 8 9 10
VALUES 1 2 3 4

我们得到以下信息:

*Main> testLayout "test.dat" 
TABLE test COLUMNS a b c VALUES 1 2 3 VALUES 4 5 6
TABLE another COLUMNS x y z q VALUES 7 8 9 10 VALUES 1 2 3 4

这似乎是你想要的?

【讨论】:

  • 这正是我想要的! =) 我希望自己创建这个解析器,但我意识到这可能比摆弄我的初级水平需要更多的工作。 ^^
【解决方案2】:

这个答案是literate Haskell,因此您可以将其复制并粘贴到名为table.lhs 的文件中以获取工作程序。

从一些导入开始

> import Control.Arrow ((&&&))
> import Control.Monad (forM_)
> import Data.List (intercalate,isPrefixOf)
> import Data.Maybe (fromJust)

假设我们用以下记录表示一个表:

> data Table = Table { tblName :: String
>                    , tblCols :: [String]
>                    , tblVals :: [String]
>                    }
>   deriving (Show)

即我们记录表名、列名列表、列值​​列表。

输入中的每个表都以TABLE 开头的行开始,因此将输入中的所有行相应地分成块:

> tables :: [String] -> [Table]
> tables [] = []
> tables xs = next : tables ys
>   where next = mkTable (th:tt)
>         (th:rest) = dropWhile (not . isTable) xs
>         (tt,ys) = break isTable rest
>         isTable = ("TABLE" `isPrefixOf`)

将输入分块到表中后,给定表的名称是TABLE 行的第一个单词。列名是出现在COLUMNS行上的所有单词,列值来自VALUES行:

> mkTable :: [String] -> Table
> mkTable xs = Table name cols vals
>   where name = head $ fromJust $ lookup "TABLE" tagged
>         cols = grab "COLUMNS"
>         vals = grab "VALUES"
>         grab t = concatMap snd $ filter ((== t) . fst) tagged
>         tagged = map ((head &&& tail) . words)
>                $ filter (not . null) xs

给定Table 记录,我们通过将名称、值和 SQL 关键字以适当的顺序粘贴到一行中来打印它:

> main :: IO ()
> main = do
>   input <- readFile "input"
>   forM_ (tables $ lines input) $
>     \t -> do putStrLn $ intercalate " " $
>                 "TABLE"   : (tblName t)  :
>                ("COLUMNS" : (tblCols t)) ++
>                ("VALUES"  : (tblVals t))

鉴于缺乏想象力的输入

表名_of_table

COLUMNS first_column 2nd_column [..] n-th_column

VALUES 1st_value 2nd_value [...] 第 n 个值

VALUES yet_another_value ... 继续

表名_of_table

COLUMNS first_column 2nd_column [..] n-th_column

VALUES 1st_value 2nd_value [...] 第 n 个值

VALUES yet_another_value ...继续

输出是

$ runhaskell table.lhs
TABLE name_of_table COLUMNS first_column 2nd_column [..] n-th_column VALUES 1st_value 2nd_value [...] n-th value yet_another_value ... 继续
TABLE name_of_table COLUMNS first_column 2nd_column [..] n-th_column VALUES 1st_value 2nd_value [...] n-th value yet_another_value ...继续

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-15
    • 2018-03-03
    • 2014-07-05
    • 1970-01-01
    • 2017-08-19
    • 2022-01-01
    • 1970-01-01
    • 2020-01-13
    相关资源
    最近更新 更多