在解析器组合器中看到Scala的“repsep”有问题

时间:2011-03-28 14:43:13

标签: regex parsing scala upnp

请帮忙!我正在尝试构建一个解析器来解析UPnP protocol中定义的SSDP消息。 (参见“发现”部分)

基本上它是HTTP OK的标题,后跟名称:值对,最后是一个空行。

在大约5000种组合之后,这是我认为“应该”工作的组合: *

 
class SsdpParser() extends JavaTokenParsers {

def fulldoc: Parser[SsdpMessage] = header ~ nameValuePairs <~ "\r\n" ^^ { case header ~ values => SsdpMessage(header, values) }

def nameValuePairs:Parser[List[(String, String)]] = repsep(nameValuePair, "\r\n")

def nameValuePair:Parser[(String, String)] = ( //name ("""[-a-zA-Z0-9.]*""".r <~ ":") //value ~ """[a-zA-Z0-9:/,_; [].-\"\'\?=]*""".r ) ^^ { case name ~ value => (name, value) }

def header: Parser[SsdpType] = (notifyLine | okLine | mSearch) def notifyLine:Parser[SsdpType] = "NOTIFY * HTTP/1.1\r\n" ^^ (x =>Notify) def mSearch:Parser[SsdpType] = "M-SEARCH * HTTP/1.1\r\n" ^^ (x=>Search) def okLine:Parser[SsdpType] = "HTTP/1.1 200 OK\r\n" ^^ (x=>OK)

}

然而,当它运行时,它看起来像是在第一个名字/值对上窒息

  

失败:[3.1]失败:字符串匹配正则表达式\r\n' expected but   '找到了

     

日期:星期一,2011年3月28日06:37:31 GMT

     

^

找到一个换行符,为什么不匹配?是的,我已经在规范和接收的实际数据中验证了两个字符(UTF-8中的a.k.a 0x0d 0x0a)。

示例数据转储在此处: *

HTTP/1.1 200 OK
Cache-Control: max-age=300
Date: Mon, 28 Mar 2011 06:37:31 GMT
Ext: 
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
Server: POSIX UPnP/1.0 DD-WRT Linux/V24
ST: urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
USN: uuid:01A0DDA7-7404-815B-63C4-539B920D5E56::urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1

0000 00 50 8d b5 2b df 00 12 17 39 a2 17 08 00 45 00 .P..+....9....E. 0010 01 83 00 00 40 00 40 11 b5 f0 c0 a8 01 01 c0 a8 ....@.@......... 0020 01 28 07 6c cf 07 01 6f 7d b8 48 54 54 50 2f 31 .(.l...o}.HTTP/1 0030 2e 31 20 32 30 30 20 4f 4b 0d 0a 43 61 63 68 65 .1 200 OK..Cache 0040 2d 43 6f 6e 74 72 6f 6c 3a 20 6d 61 78 2d 61 67 -Control: max-ag 0050 65 3d 33 30 30 0d 0a 44 61 74 65 3a 20 53 75 6e e=300..Date: Sun 0060 2c 20 32 37 20 4d 61 72 20 32 30 31 31 20 30 38 , 27 Mar 2011 08 0070 3a 34 37 3a 33 34 20 47 4d 54 0d 0a 45 78 74 3a :47:34 GMT..Ext: 0080 20 0d 0a 4c 6f 63 61 74 69 6f 6e 3a 20 68 74 74 ..Location: htt 0090 70 3a 2f 2f 31 39 32 2e 31 36 38 2e 31 2e 31 3a p://192.168.1.1: 00a0 31 37 38 30 2f 49 6e 74 65 72 6e 65 74 47 61 74 1780/InternetGat 00b0 65 77 61 79 44 65 76 69 63 65 2e 78 6d 6c 0d 0a ewayDevice.xml.. 00c0 53 65 72 76 65 72 3a 20 50 4f 53 49 58 20 55 50 Server: POSIX UP 00d0 6e 50 2f 31 2e 30 20 44 44 2d 57 52 54 20 4c 69 nP/1.0 DD-WRT Li 00e0 6e 75 78 2f 56 32 34 0d 0a 53 54 3a 20 75 72 6e nux/V24..ST: urn 00f0 3a 73 63 68 65 6d 61 73 2d 75 70 6e 70 2d 6f 72 :schemas-upnp-or 0100 67 3a 73 65 72 76 69 63 65 3a 57 41 4e 43 6f 6d g:service:WANCom 0110 6d 6f 6e 49 6e 74 65 72 66 61 63 65 43 6f 6e 66 monInterfaceConf 0120 69 67 3a 31 0d 0a 55 53 4e 3a 20 75 75 69 64 3a ig:1..USN: uuid: 0130 30 31 41 30 44 44 41 37 2d 37 34 30 34 2d 38 31 01A0DDA7-7404-81 0140 35 42 2d 36 33 43 34 2d 35 33 39 42 39 32 30 44 5B-63C4-539B920D 0150 35 45 35 36 3a 3a 75 72 6e 3a 73 63 68 65 6d 61 5E56::urn:schema 0160 73 2d 75 70 6e 70 2d 6f 72 67 3a 73 65 72 76 69 s-upnp-org:servi 0170 63 65 3a 57 41 4e 43 6f 6d 6d 6f 6e 49 6e 74 65 ce:WANCommonInte 0180 72 66 61 63 65 43 6f 6e 66 69 67 3a 31 0d 0a 0d rfaceConfig:1... 0190 0a

2 个答案:

答案 0 :(得分:1)

正如jrudolph所说,RegexParsers(及其子类JavaTokenParsers)默认跳过空格。您可以选择通过覆盖skipWhitespace告诉它不要跳过空格,并且可以选择通过覆盖受保护的{{1}来告诉它您认为是空白的内容。 }}

问题来自于:

val whiteSpace: Regex

此处,def nameValuePairs:Parser[List[(String, String)]] = repsep(nameValuePair, "\r\n") 被自动跳过,因此永远不会找到它。更改\r\n后,您会收到错误,因为文件末尾有一个额外的skipWhitespace,所以它希望看到另一个\r\n

你可能会有更好的运气:

nameValuePair

或者,您可以完全删除def nameValuePairs:Parser[List[(String, String)]] = rep(nameValuePair <~ "\r\n") 并让解析器跳过空格。

答案 1 :(得分:0)

快速浏览一下后,有三条建议:

    如果您不使用JavaTokenParser中的任何解析器,
  • 使用RegexParsers而不是JavaTokenParsers就足够了
  • RegexParsers默认跳过空格;覆盖skipWhitespace以更改该行为
  • 对于另一个选项,看看parboiled,它有一个与解析器组合器类似的语法,并且有很好的文档记录,但IMO更准备生产,具有更好的性能和错误报告(免责声明:我使用一个人背后的家伙)