P96 - 检查 Ada 标识符语法

2026-09-07 00:00    #Haskell   #99题   #解析  

P96 - 检查 Ada 标识符语法

Syntax checking for Ada identifiers

官方模块:Problems.P96 核心函数:isIdentifier


← P95 英文数字单词 | P97 数独 →


语法规则

标识符必须以英文字母开头,之后可以包含字母、数字和下划线;下划线不能连续,也不能位于末尾。

实现

方法一:递归解析

 1isIdentifier :: String -> Bool
 2isIdentifier [] = False
 3isIdentifier (first:rest) = asciiLetter first && consume False rest
 4  where
 5    consume previousUnderscore [] = not previousUnderscore
 6    consume previousUnderscore (c:cs)
 7      | asciiLetter c || asciiDigit c = consume False cs
 8      | c == '_' && not previousUnderscore = consume True cs
 9      | otherwise = False
10
11asciiLetter c = c `elem` ['A'..'Z'] || c `elem` ['a'..'z']
12asciiDigit c  = c `elem` ['0'..'9']

状态 previousUnderscore 记录前一个字符是否为下划线;输入结束时它还为真,就说明标识符以下划线结尾。

方法二:按下划线分组

 1isIdentifier :: String -> Bool
 2isIdentifier input = case splitUnderscores input of
 3  [] -> False
 4  firstGroup : groups ->
 5    not (null firstGroup)
 6    && asciiLetter (head firstGroup)
 7    && all validGroup (firstGroup : groups)
 8  where
 9    validGroup group =
10      not (null group) && all (\c -> asciiLetter c || asciiDigit c) group
11
12splitUnderscores :: String -> [String]
13splitUnderscores = foldr step [""]
14  where
15    step '_' groups = "" : groups
16    step c (group : groups) = (c : group) : groups
17    step _ [] = []

连续下划线、开头下划线或结尾下划线都会产生空分组,因此只需检查每组非空,再检查组内字符。首组还要额外保证第一个字符是字母。这个实现不依赖正则表达式包。

方法对比

方法状态
递归解析记录前一个字符是否为下划线
分组验证用空分组表示非法下划线位置

测试

 1>>> isIdentifier "this_is_a_long_identifier"
 2True
 3>>> isIdentifier "This_ends_in_an_underscore_"
 4False
 5>>> isIdentifier "This__has__two__underscores"
 6False
 7>>> isIdentifier "1234"
 8False
 9>>> isIdentifier "Fibonacci_sequence_1_1_2_3_5_8"
10True

算法单次扫描字符串,时间复杂度 O(n)O(n)

参考


← P95 英文数字单词 | P97 数独 →