-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path4.3.9.hs
134 lines (105 loc) · 5.93 KB
/
4.3.9.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
module Demo where
import Data.List.Split
import Data.Char
-- import Data.Time.Clock
-- import Data.Time.Format
-- import System.Locale
-- timeToString :: UTCTime -> String
-- timeToString = formatTime defaultTimeLocale "%a %d %T"
-- data LogLevel = Error | Warning | Info deriving Show
-- data LogEntry = LogEntry { timestamp :: UTCTime, logLevel :: LogLevel, message :: String }
-- logLevelToString :: LogLevel -> String
-- logLevelToString = show
-- logEntryToString :: LogEntry -> String
-- logEntryToString le = (timeToString $ (timestamp le)) ++ ": " ++ (logLevelToString $ (logLevel le)) ++ ": " ++ (message le)
data Shape = Circle Double | Rectangle Double Double
isRectangle :: Shape -> Bool
isRectangle Rectangle{} = True
isRectangle _ = False
data Person = Person { firstName :: String, lastName :: String, age :: Int } deriving Show
abbrFirstName :: Person -> Person
abbrFirstName p =
if (length $ firstName p) <= 2 then
p
else
p { firstName = ((head $ firstName p) : ".") }
{-
Реализуйте функцию parsePerson, которая разбирает строки вида firstName = John\nlastName = Connor\nage = 30 и возвращает либо результат типа Person, либо ошибку типа Error.
Строка, которая подается на вход, должна разбивать по символу '\n' на список строк, каждая из которых имеет вид X = Y. Если входная строка не имеет указанный вид, то функция должна возвращать ParsingError.
Если указаны не все поля, то возвращается IncompleteDataError.
Если в поле age указано не число, то возвращается IncorrectDataError str, где str — содержимое поля age.
Если в строке присутствуют лишние поля, то они игнорируются.
-}
data Error = ParsingError | IncompleteDataError | IncorrectDataError String deriving Show
--data Person = Person { firstName :: String, lastName :: String, age :: Int }
parsePerson :: String -> Either Error Person
parsePerson str = if isValidStr str == False then
Left ParsingError
else if (hasAllFields fields pairs') == False then
Left IncompleteDataError
else if ageIsCorrect str == False then
Left (IncorrectDataError $ snd (valueOf "age" pairs'))
else
Right Person {
lastName = snd $ valueOf "lastName" pairs',
firstName = snd $ valueOf "firstName" pairs',
age = (read (snd $ valueOf "age" pairs')::Int)
}
where
pairs' = pairs str
fields = ["lastName", "firstName", "age"]
pairs str = map (\(key:value:[]) -> (key,value)) (filter isPair (map keyValues (fields str)))
isPair str = length str == 2
fields = splitOn "\n"
keyValues str = let
s1 = splitOn " = " str
s2 = splitOn " =" str
in
if (length s1) == 0 then
s2
else
s1
isValidStr str = (length $ pairs str) > 0 && isValidFields str && (length (snd (age' str)) > 0)
valueOf key pairs = head (filter (\(key',_) -> key' == key) pairs)
isNumber' str = all (True ==) (map isDigit str) && length str > 0
hasAllFields fields pairs = all (True ==) (map (\f -> hasField f pairs) fields)
hasField field pairs = length (filter (\(key,_) -> key == field) pairs) > 0
age' str = valueOf "age" (pairs str)
ageIsCorrect str = isNumber' (snd (age' str))
isValidFields str = all (True==) (map (\f -> ((length (splitOn "=" f)) > 0) && ((length (splitOn " = " f)) > 0)) (fields str))
-- wrong Parse | empty string
t0 = parsePerson ""
-- correct
t1 = parsePerson "firstName = John\nlastName = Connor\nage = 30"
-- wrong Parse | no spaces around = in minor fields
t2 = parsePerson "firstName = John Smith\nlastName = Connor\nage = 30\nasde=as11"
-- wrong Parse | no spaces around = in major fields
t3 = parsePerson "firstName=Barbarian\nlastName=Conn On\nage=30"
-- wrong Incorrect | age is non-numeric
t4 = parsePerson "firstName = John\nlastName = Connor\nage = as30"
-- wrong Parse | no spaces around = on the left in minor fields
t5 = parsePerson "firstName = John Smith\nlastName = Connor\nage = 30\nasde= "
-- wrong Parse | no spaces around = in major fields, missing major field
t6 = parsePerson "firstName=Barbarian\nlastName=Conn Or"
-- wrong Parse | no spaces around = in major fields, typo in major field
t7 = parsePerson "firstNameee = John Smith\nlastName = Connor\nage = 30\nasde=as11"
-- correct | excessive fields
t8 = parsePerson "firstName = John\nlastName = Connor\nfoo = bar\nage = 30"
-- wrong Incomplete | missing major field
t9 = parsePerson "firstName = Barbarian\nlastName = Conn Or"
-- wrong Parse | empty major value
t10 = parsePerson "firstName = John\nlastName = Connor\nage = "
-- wrong Parse | no spaces around = on the right in major field
t11 = parsePerson "firstName = John\nlastName = Connor\nage ="
-- wrong Parse | empty key, missing major field
t12 = parsePerson "firstName = John\nlastName = Connor\n = 30"
-- correct | spaces in major field value
t13 = parsePerson "firstName = Barbarian\nlastName = Conn On\nage = 30"
-- correct | = in major field value
t14 = parsePerson "firstName = John\nlastName = Con=nor\nage = 30"
-- wrong Parse | no spaces around =, missing value in minor field
t15 = parsePerson "firstName=Barbarian\nlastName=Conn On\nage=30\ng dsfsd"
-- wrong Incomplete | major field key with whitespace, age is non-numeric
t17 = parsePerson " firstName = John\nlastName = Connor\nage = 2f8 "
-- correct | shiffled fields
t18 = parsePerson "lastName = Connor\nfirstName = John\nage = 30"