読者です 読者をやめる 読者になる 読者になる

Parser CombinatorsでIPv4のパース

Scala

パーサーを指定回数適用するrepNと、最後の"."をoptionalにするだけでわりと簡単に書けました。

import scala.util.parsing.combinator.syntactical._

object Main extends StandardTokenParsers {
    lexical.delimiters ++= List(".")

    def parse : Parser[List[String]] = repN(4, numericLit <~ opt("."))

    def parseIp(s : String) : List[String] = {
        parse(new lexical.Scanner(s)) match {
            case Success(result, _) => return result
            case Failure(msg, _) => println("failure : " ++ msg)
            case Error(msg, _) => println("error : " ++ msg)
        }
        return List()
    }

    def main(args: Array[String]) {
        val ip : List[String] = parseIp("192.168.0.1")
        ip foreach println
    }
}
192
168
0
1


整数型のリストとしてほしい場合は、パース時にtoInt。

import scala.util.parsing.combinator.syntactical._

object Main extends StandardTokenParsers {
    lexical.delimiters ++= List(".")

    def parse : Parser[List[Int]] = repN(4, numericLit <~ opt(".") ^^ { _.toInt })

    def parseIp(s : String) : List[Int] = {
        parse(new lexical.Scanner(s)) match {
            case Success(result, _) => return result
            case Failure(msg, _) => println("failure : " ++ msg)
            case Error(msg, _) => println("error : " ++ msg)
        }
        return List()
    }

    def main(args: Array[String]) {
        val ip : List[Int] = parseIp("192.168.0.1")
        ip foreach println
    }
}

numericLitは、Parser[Int]が返ってきてほしい。


Parser[Int]が返されるintLit書いてみました。

import scala.util.parsing.combinator.syntactical._

object Main extends StandardTokenParsers {
    lexical.delimiters ++= List(".")

    def intLit : Parser[Int] = elem("number", _.isInstanceOf[lexical.NumericLit]) ^^ (_.chars.toInt)

    def parse : Parser[List[Int]] = repN(4, intLit <~ opt("."))

    def parseIp(s : String) : List[Int] = {
        parse(new lexical.Scanner(s)) match {
            case Success(result, _) => return result
            case Failure(msg, _) => println("failure : " ++ msg)
            case Error(msg, _) => println("error : " ++ msg)
        }
        return List()
    }

    def main(args: Array[String]) {
        val ip : List[Int] = parseIp("192.168.0.1")
        ip foreach println
    }
}

型のパーサーは用意されてるのが不便なので自作したほうがいいかもしれない。