Skip to content

Latest commit

 

History

History
147 lines (107 loc) · 7.38 KB

MdTable.md

File metadata and controls

147 lines (107 loc) · 7.38 KB

Форматиране на данни в Markdown таблица

Markdown е средтво за писане на свободен текст, в който обикновени символи се използват за форматиране. Поради лесния си и интуитивен синтаксис е широко ползван за форматиране на съобщения във форуми, блогове, GitHub и на много други места.

Целта на текущото упражнение е да се създаде функцията layoutTable, която подпомага поддържането на добре форматирана таблица. В Markdown таблицатите представляват ASCII art, в който | се използва като разделител на колона, а ред от - разделител на заглавната част.

Пример:

| Column 1                | Column 2                |
| ----------------------- | ----------------------- |
| This is cell #1, row #1 | This is cell #2, row #1 |
| This is cell #1, row #2 | This is cell #2, row #2 |

Процесираният Markdown резултат е:

Column 1 Column 2
This is cell #1, row #1 This is cell #2, row #1
This is cell #1, row #2 This is cell #2, row #2

Защо?

Поддържането на големи добре форматирани таблици е пипкава и досадна задача. Затова процедурното им генериране изглежда като най-логичната идея. Функцията layoutTable прави точно това - тя получава списък от редове (първият е заглавната част (header), а останалите тялото) и връща текста на добре подравнена таблица. Всеки от редовете сам по себе си е списък от клетки (стойностите за съответната колона) [String].

layoutTable :: [[String]] -> String
table1 = [
    [ "Column 1",                "Column 2" ],
    [ "This is cell #1, row #1", "This is cell #2, row #1" ],
    [ "This is cell #1, row #2", "This is cell #2, row #2" ]
  ]
> putStr (layoutTable table1)
| Column 1                | Column 2                |
| ----------------------- | ----------------------- |
| This is cell #1, row #1 | This is cell #2, row #1 |
| This is cell #1, row #2 | This is cell #2, row #2 |

Допълнителни изисквания

Подаденият списък на layoutTable може да съдържа редове с различен брой колони, а колоните не са предварително подравнени. Това остава задача за функцията - да уравни брой колони в редовете и ширината на клетките в колоната. За улеснение, нека всички колони станат толкова широки, колкото най-широката от тях.

Пример:

table2 = [
    [ "Item", "Price" ],
    [ "iPhone", "$1", "Not in stock" ],
    [ "iPad",   "$599" ],
    [ "CAUTION: It's a scam!" ]
  ]
> putStr (layoutTable table2)
| Item                  | Price                 |                       |
| --------------------- | --------------------- | --------------------- |
| iPhone                | $1                    | Not in stock          |
| iPad                  | $599                  |                       |
| CAUTION: It's a scam! |                       |                       |

Идея за имплементация

В Haskell лесно се създават решения, като поредица от стъпки, които трансформират входа. Този подход много прилича на поточна линия или на pipes в Unix. Текущата задача също може да бъде погледната в такава светлина. Фунцкията layoutTable може да се реализира чрез поредица от следните действия:

  • уравняване броя колони (equalizeColumnCount :: [[String]] -> [[String]])
  • уравняване големината на колоните (equalizeColumnSize :: [[String]] -> [[String]])
  • добавяне на ред межди заглавието и тялото
  • трансформиране на списъка от колони до списък от редове (toLine :: [String] -> String)
  • използване на функцията unlines от Prelude за слепване на списъка от редове до String

padWith

Тъй като на много места ни е нужно да "подравняваме" е добре това да го направим с генерализирана функция. Тя трябва да приеме елемент от типа на списъка x :: a, минимална големина на крайния списък minSize :: Int и списък xs :: [a], който да подравни до исканата големина. Ако подаденият списък е по-голям от minSize, то той трябва да бъде върнат непроменен.

padWith :: a -> Int -> [a] -> [a]
> padWith 'x' 5 "123"
"123xx"

> padWith 'x' 3 "12345"
"12345"

> padWith "x" 5 ["a", "b", "c" ]
["a", "b", "c", "x", "x" ]

Други функции

Може да намерите за полезни следните функции:

  • maximum - имплементирахме я в упражнението за списъци, връща най-големия елемент от списъка
  • intercalate - може да се ползва за слепване масив от низове [String] с подаден String
> maximum [10, 20, 30]
30

> intercalate " -> " [ "a", "b", "c" ]
"a -> b -> c"

Още няколко думи за тестване

Също както и Lists това упражнение има тестове. Този път тестовете използват външна библиотека - HSpec. За да инсталирате HSpec, използвайте cabal (пакетния мениджър на Haskell).

$ cabal update & cabal install hspec

Пускането на тестовете може да стане по два начина:

$ ghci
> :l MdTableTests.hs
> main

или директно с:

$ runhaskell MdTableTests.hs

Препоръчваме първия вариант.

ВАЖНО: Ако имате проблеми с инсталацията на hspec, моля потърсете помощ! При оплитане на версиите с cabal, haskell инсталацията Ви може да стане неизползваема.