перестановка строки, содержащей повторяющиеся узоры переменной длины - PullRequest
2 голосов
/ 03 августа 2010

У меня есть файл со следующим макетом:

TABLE name_of_table

КОЛОННЫ first_column 2nd_column [..] n-th_column

ЗНАЧЕНИЯ 1st_value 2nd_value [...] n-ое значение

VALUES Yet_another_value ... перейти на

ДРУГОЙ СТОЛ повторить с начала .....

Я хочу перестроить этот текстовый файл, поэтому мне не нужно вводить TABLE и COLUMNS перед каждой строкой VALUES, получая:

TABLE name_of_table COLUMNS first_column [..] n-й столбец VALUES 1st_value

TABLE name_of_table COLUMNS first_column [..] n-й столбец VALUES butanother_value

Мне нужно взять ввод и переставить несколько строк одновременно, поэтому получение всего текстового файла в виде строки с hGetContents кажется подходящим, с получением строки, подобной этой:

TABLE name_of_table COLUMNS first_column [..] n-th_column VALUES 1st_value [..] n-th_value VALUES another_value [..] still_another VALUES ...... ДРУГОЙ СТОЛ .... COLUMNS .... VALUES [ ....] ЦЕННОСТИ ...

Я пытался сделать это с вложенным случаем и рекурсией. Это дает мне дилемму, с которой мне нужна помощь:

1) Мне нужна рекурсия, чтобы избежать бесконечных проблем с вложением кейсов.

2) с рекурсией я не могу альтернативно добавить предыдущие части строки, так как рекурсия ссылается только на хвост моей строки!

Иллюстрирование проблемы:

</p>

<code>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)
</code>

Я получаю FIRSTPART, VALUES VALUES VALUES VALUES, и я не могу снова получить FIRSTPART, чтобы создать FIRSTPART, VALUES, FIRSTPART, VALUES, FIRSTPART, VALUES.

Попытка сделать это путем ссылки на myStr в valueRecursion явно выходит за рамки.

Что делать ??

Ответы [ 2 ]

2 голосов
/ 03 августа 2010

Для меня проблема такого рода была бы за порогом использования инструмента реального анализа.Вот быстрый пример работы с 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

Что, кажется, то, что вы хотите?

0 голосов
/ 03 августа 2010

Этот ответ грамотный 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))

При неимитирующем вводе

TABLE name_of_table

COLUMNS first_column 2nd_column [..] n-th_column

VALUES 1st_value 2nd_value [...] n-th value

VALUES yet_another_value ... go on

TABLE name_of_table

COLUMNS first_column 2nd_column [..] n-th_column

VALUES 1st_value 2nd_value [...] n-th value

VALUES yet_another_value ... go on

вывод составляет

$ 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 ... go on
TABLE name_of_table COLUMNS first_column 2nd_column [..] n-th_column VALUES 1st_value 2nd_value [...] n-th value yet_another_value ... go on
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...