为了使用OperatorPrecedenceParser
实现不区分大小写的中缀运算符,我正在预处理输入,将其解析为由字符串文字分隔的文本。然后在文本部分中搜索需要大写的中缀运算符(以符合OPP
已知的运算符)。然后进行实际的解析。
我的问题是,两个阶段都可以组合成一个解析器吗?我试过了
// preprocess: Parser<string,_>
// scalarExpr: Parser<ScalarExpr,_>
let filter = (preprocess .>> eof) >>. (scalarExpr .>> eof)
但它在输入结束时失败,似乎期待scalarExpr
。输入可以由preprocess
和scalarExpr
独立解析,所以我猜这是eof
的问题,但我似乎无法做到正确。这可能吗?
以下是其他解析器供参考。
let stringLiteral =
let subString = manySatisfy ((<>) '"')
let escapedQuote = stringReturn "\"\"" "\""
(between (pstring "\"") (pstring "\"") (stringsSepBy subString escapedQuote))
let canonicalizeKeywords =
let keywords =
[
"OR"
"AND"
"CONTAINS"
"STARTSWITH"
"ENDSWITH"
]
let caseInsensitiveKeywords = HashSet(keywords, StringComparer.InvariantCultureIgnoreCase)
fun text ->
let re = Regex(@"([\w][\w']*\w)")
re.Replace(text, MatchEvaluator(fun m ->
if caseInsensitiveKeywords.Contains(m.Value) then m.Value.ToUpperInvariant()
else m.Value))
let preprocess =
stringsSepBy
((manySatisfy ((<>) '"')) |>> canonicalizeKeywords)
(stringLiteral |>> (fun s -> "\"" + s + "\""))
答案 0 :(得分:1)
使用FParsec的OperatorPrecedenceParser解析不区分大小写的运算符的最简单方法是为要支持的每个大小写添加运算符定义。如果您只需要支持短操作员名称,例如“和”或“或”,则可以简单地添加所有可能的案例组合。如果您想使用对于此方法来说太长的运算符名称,您可能会考虑仅支持理智的外壳,即小写,大写,camelCase和PascalCase。当您想要支持多个外壳时,通常可以方便地编写一个辅助函数,从标准函数中自动生成所有需要的外壳。
如果你有很长的运营商名称并且你真的想支持所有套管,OperatorPrecedenceParser
的动态可配置性也允许采用以下方法,这比转换输入更容易,更有效:
OperatorPrecedenceParser
。 (通常不会有很多相同运营商的外壳。)OperatorPrecedenceParser
解析输入。 解析多个输入时,您可以保留OperatorPrecedenceParser
实例,并根据需要懒洋洋地添加新的运算符框。