忽略 JavaToken 组合器解析器中的前缀
Ignoring prefixes in a JavaToken combinator parser
我正在尝试使用 JavaToken 组合器解析器提取位于较大字符串中间的特定匹配项(即忽略一组随机前缀字符)。但是我无法让它工作并且认为我被贪婪的解析器 and/or CRs LFs 抓住了。 (前缀字符基本上可以是任何东西)。我有:
class RuleHandler extends JavaTokenParsers {
def allowedPrefixChars = """[a-zA-Z0-9=*+-/<>!\_(){}~\s]*""".r
def findX: Parser[Double] = allowedPrefixChars ~ "(x=" ~> floatingPointNumber <~ ")" ^^ { case num => num.toDouble}
}
然后在我的测试用例中..
"when looking for the X value" in {
"must find and correctly interpret X" in {
val testString =
"""
|Looking (only)
|for (x=45) within
|this string
""".stripMargin
val answer = ruleHandler.parse(ruleHandler.findX, testString)
System.out.println(" X value is : " + answer.toString)
}
}
我认为它类似于 this SO question。任何人都可以看到有什么问题吗?谢谢。
首先,你不应该在 """ """
:
中两次转义 "\s"
def allowedPrefixChars = """[a-zA-Z0-9=*+-/<>!\_(){}~\s]*?""".r
在你的情况下,它被单独解释 "\"
或 "s"
(s
作为符号,而不是 \s
)
其次,您的 allowedPrefixChars
解析器包括 (
、x
、=
,因此它捕获了整个字符串,包括 (x=
,没有留下任何内容到后续的解析器。
解决方案是更具体地说明您想要的前缀:
object ruleHandler extends JavaTokenParsers {
def allowedPrefixChar: Parser[String] = """[a-zA-Z0-9=*+-/<>!\_){}~\s]""".r //no "(" here
def findX: Parser[Double] = rep(allowedPrefixChar | "\((?!x=)".r ) ~ "(x=" ~> floatingPointNumber <~ ")" ^^ { case num => num.toDouble}
}
ruleHandler.parse(ruleHandler.findX, testString)
res14: ruleHandler.ParseResult[Double] = [3.11] parsed: 45.0
我已经告诉解析器忽略 (
,后面有 x=
(只是 negative lookahead)。
选择:
"""\(x=(.*?)\)""".r.findAllMatchIn(testString).map(_.group(1).toDouble).toList
res22: List[Double] = List(45.0)
如果您想正确使用解析器,我建议您描述整个 BNF 语法(包括所有可能的 (
、)
和 =
用法)——而不仅仅是片段.例如,如果它是关键字,则将 (only)
包含到您的解析器中,"(" ~> valueName <~ "=" ~ value
以获得值。不要忘记 scala-parser 旨在 return 你的 AST,而不仅仅是一些匹配的值。纯正则表达式更适合从非结构化数据进行正则匹配。
如何以正确的方式使用解析器的示例(未尝试编译):
trait Command
case class Rule(name: String, value: Double) extends Command
case class Directive(name: String) extends Command
class RuleHandler extends JavaTokenParsers { //why `JavaTokenParsers` (not `RegexParsers`) if you don't use tokens from Java Language Specification ?
def string = """[a-zA-Z0-9*+-/<>!\_{}~\s]*""".r //it's still wrong you should use some predefined Java-like literals from **JavaToken**Parsers
def rule = "(" ~> string <~ "=" ~> string <~ ")" ^^ { case name ~ num => Rule(name, num.toDouble} }
def directive = "(" ~> string <~ ")" ^^ { case name => Directive(name) }
def commands: Parser[Command] = repsep(rule | directive, string)
}
如果您需要处理自然语言(Chomsky type-0), scalanlp 或类似的东西更合适。
我正在尝试使用 JavaToken 组合器解析器提取位于较大字符串中间的特定匹配项(即忽略一组随机前缀字符)。但是我无法让它工作并且认为我被贪婪的解析器 and/or CRs LFs 抓住了。 (前缀字符基本上可以是任何东西)。我有:
class RuleHandler extends JavaTokenParsers {
def allowedPrefixChars = """[a-zA-Z0-9=*+-/<>!\_(){}~\s]*""".r
def findX: Parser[Double] = allowedPrefixChars ~ "(x=" ~> floatingPointNumber <~ ")" ^^ { case num => num.toDouble}
}
然后在我的测试用例中..
"when looking for the X value" in {
"must find and correctly interpret X" in {
val testString =
"""
|Looking (only)
|for (x=45) within
|this string
""".stripMargin
val answer = ruleHandler.parse(ruleHandler.findX, testString)
System.out.println(" X value is : " + answer.toString)
}
}
我认为它类似于 this SO question。任何人都可以看到有什么问题吗?谢谢。
首先,你不应该在 """ """
:
"\s"
def allowedPrefixChars = """[a-zA-Z0-9=*+-/<>!\_(){}~\s]*?""".r
在你的情况下,它被单独解释 "\"
或 "s"
(s
作为符号,而不是 \s
)
其次,您的 allowedPrefixChars
解析器包括 (
、x
、=
,因此它捕获了整个字符串,包括 (x=
,没有留下任何内容到后续的解析器。
解决方案是更具体地说明您想要的前缀:
object ruleHandler extends JavaTokenParsers {
def allowedPrefixChar: Parser[String] = """[a-zA-Z0-9=*+-/<>!\_){}~\s]""".r //no "(" here
def findX: Parser[Double] = rep(allowedPrefixChar | "\((?!x=)".r ) ~ "(x=" ~> floatingPointNumber <~ ")" ^^ { case num => num.toDouble}
}
ruleHandler.parse(ruleHandler.findX, testString)
res14: ruleHandler.ParseResult[Double] = [3.11] parsed: 45.0
我已经告诉解析器忽略 (
,后面有 x=
(只是 negative lookahead)。
选择:
"""\(x=(.*?)\)""".r.findAllMatchIn(testString).map(_.group(1).toDouble).toList
res22: List[Double] = List(45.0)
如果您想正确使用解析器,我建议您描述整个 BNF 语法(包括所有可能的 (
、)
和 =
用法)——而不仅仅是片段.例如,如果它是关键字,则将 (only)
包含到您的解析器中,"(" ~> valueName <~ "=" ~ value
以获得值。不要忘记 scala-parser 旨在 return 你的 AST,而不仅仅是一些匹配的值。纯正则表达式更适合从非结构化数据进行正则匹配。
如何以正确的方式使用解析器的示例(未尝试编译):
trait Command
case class Rule(name: String, value: Double) extends Command
case class Directive(name: String) extends Command
class RuleHandler extends JavaTokenParsers { //why `JavaTokenParsers` (not `RegexParsers`) if you don't use tokens from Java Language Specification ?
def string = """[a-zA-Z0-9*+-/<>!\_{}~\s]*""".r //it's still wrong you should use some predefined Java-like literals from **JavaToken**Parsers
def rule = "(" ~> string <~ "=" ~> string <~ ")" ^^ { case name ~ num => Rule(name, num.toDouble} }
def directive = "(" ~> string <~ ")" ^^ { case name => Directive(name) }
def commands: Parser[Command] = repsep(rule | directive, string)
}
如果您需要处理自然语言(Chomsky type-0), scalanlp 或类似的东西更合适。