Возникли проблемы с "repsep" в Scala, как видно из комбинаторов синтаксического анализа - PullRequest
2 голосов
/ 28 марта 2011

Пожалуйста, помогите! Я пытаюсь создать синтаксический анализатор для анализа сообщений SSDP, как определено в протоколе UPnP . (см. раздел «Открытие»)

По сути, это заголовок HTTP OK, за которым следуют пары имя: значение и, наконец, пустая строка.

После примерно 5000 комбинаций, я думаю, что это «должно» сработать: *

 
class SsdpParser() extends JavaTokenParsers {</p>

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

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

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

<p>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)</p>

<p>}

Однако, когда он запускается, похоже, что он задыхается от самой первой пары имя / значение

Ошибка: [3.1] ошибка: регулярное выражение совпадения строк \r\n' expected but 'найдено

Дата: понедельник, 28 марта 2011 г. 06:37:31 GMT

^

Находит разрыв строки, почему это не совпадает? И да, я проверил, что оба символа (a.k.a 0x0d 0x0a в UTF-8) как в спецификации, так и в фактических полученных данных.

Пример дампа данных здесь: *

HTTP/1.1 200 OK
Cache-Control: max-age=300
Date: Mon, 28 Mar 2011 06:37:31 GMT
Ext: 
Location: <a href="http://192.168.1.1:1780/InternetGatewayDevice.xml" rel="nofollow">http://192.168.1.1:1780/InternetGatewayDevice.xml</a>
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</p>

<p>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<br>

Ответы [ 2 ]

1 голос
/ 28 марта 2011

Как сказал Джрудольф, RegexParsers (и его подкласс JavaTokenParsers) по умолчанию пропускают пробелы. У вас есть возможность запретить пропуск пробелов путем переопределения skipWhitespace, а у вас также есть возможность сказать, что вы считаете пробелами, переопределив защищенный 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")

В качестве альтернативы, вы можете удалить \r\n и разрешить парсеру пропускать пробелы.

0 голосов
/ 28 марта 2011

После быстрого взгляда три предложения:

  • с использованием RegexParsers вместо JavaTokenParsers должно быть достаточно, если вы не используете парсеры внутри JavaTokenParser
  • RegexParsers по умолчанию пропускает пробелы; переопределить skipWhitespace , чтобы изменить это поведение
  • для другого варианта, посмотрите на parboiled , он имеет синтаксис, похожий на синтаксические комбинаторы, и довольно хорошо документирован, но IMO более готов к работе, имеет лучшую производительность и отчеты об ошибках (отказ от ответственности: я работаю с парнем за кулаком)
...