将字符串标记为字符串列表,具体取决于规则集

时间:2017-05-06 18:00:19

标签: string haskell compiler-construction

我有一个字符串需要使用以下规则标记到列表中:

  • '('和')'括号
  • 带小数点数的数字
  • 运算符(+,/,*,> =等)
  • 以字母开头的标识符和字符串的其余部分可以是字母或数字

为此,我在Haskell代码中创建了上述规则作为有限状态机:

data FsaState = R | Q -- start state: Q; success state R;
  deriving Show

输入:

tokenize “( (23.5+age) ∗ (20.99+adres))”

输出:

[ “(”, “ ”, “(”, “23.5”, “+”, “age”, “)”, “ ”, “∗”, “ ”, “(”, “20.99”, “+”, “adres”, “)”, “)” ]

(可能只用空格过滤掉字符串)

我应该如何开始?由于Haskell不是我的主要语言,我陷入了强制性的思维模式。

1 个答案:

答案 0 :(得分:2)

如果您担心效率,您应该定义一个令牌数据类型(data Token = ...)。也就是说,这是一个最小化的标记器,可以完全按照您的要求进行操作。它以递归方式工作(尾部),为每个递归调用咀嚼一个令牌(或空格)。

我选择丢弃空格而不是将其变成令牌。

import Data.Char

tokenize :: String -> [String]
tokenize "" = []
tokenize (c:cs)
  | isSpace c = tokenize cs
  | isAlpha c = let (i,cs') = span isAlphaNum cs in (c : i) : tokenize cs'
  | isDigit c = let (n,cs') = span isDigit cs
                in case cs' of
                     ('.':cs'') -> let (m,cs''') = span isDigit cs''
                                   in (c : n ++ "." ++ m) : tokenize cs'''
                     _ -> (c : n) : tokenize cs'
  | c `elem` "+/*-()" = [c] : tokenize cs
  | otherwise = error $ "unexpected character " ++ show c

以下是行动:

ghci> tokenize "( (23.5+age) ∗ (20.99+adres))"
["(","(","23.5","+","age",")","*","(","20.99","+","adres",")",")"]

那说:我强烈建议您编写一个解析monad(类似data Parser a = Parser { runParser :: String -> Maybe (a,String) }),以便您可以单独编写解析器,或使用现有的库/工具(请参阅Alex特别是megaparsec