2012-11-13 26 views
12

Listeler bir veya daha fazla boş satır ile ayrılır, yeni satır sınırlandırılmış kelime listeleri okur bir Scala çözümleyici dilbilgisi dilbilgisi yazıyorum. Ben List(List(cat, mouse, horse), List(apple, orange, pear)) dönmek istiyorumScala ayrıştırıcı birleştiriciler ve yeni satır sınırlı metin

cat 
mouse 
horse 

apple 
orange 
pear 

: aşağıdaki dizeyi göz önüne alındığında.

Kelime listelerini yeni satır sınırlandırılmış kelimeler olarak değerlendiren bu temel dilbilgisini yazdım. whitespace'un varsayılan tanımını geçersiz kılmam gerektiğine dikkat edin. Bu

[8.1] parsed: List(List(cat, mouse, horse), List(), List(apple, orange, pear)) 

döner yani

import util.parsing.combinator.RegexParsers 

object WordList extends RegexParsers { 

    private val eol = sys.props("line.separator") 

    override val whiteSpace = """[ \t]+""".r 

    val list: Parser[List[String]] = repsep("""\w+""".r, eol) 

    val lists: Parser[List[List[String]]] = repsep(list, eol) 

    def main(args: Array[String]) { 
     val s = 
      """cat 
      |mouse 
      |horse 
      | 
      |apple 
      |orange 
      |pear""".stripMargin 

     println(parseAll(lists, s)) 
    } 
} 

Bu, yanlış, boş bir kelime listeleri gibi boş satır davranır (orta boş bir liste unutmayın.)

En çizgi isteğe bağlı bir son vermek her listenin sonu.

val list: Parser[List[String]] = repsep("""\w+""".r, eol) <~ opt(eol) 

Bu liste arasında tek bir boş satır olmadığı durumlarda kolları, ancak birden çok boş satır ile aynı sorun vardır.

val lists:Parser[List[List[String]]] = repsep(list, rep(eol)) 

ancak bu, yukarıdaki giriş asılı:

birden fazla sonu hattı sınırlayıcıları izin vermek için lists tanımını değiştirme çalıştı.

Sınırlayıcı olarak birden çok boş satırı işleyebilecek doğru dilbilgisi nedir?

cevap

13

Beyaz boşluk tanımını yeniden tanımlamak yerine skipWhitespace ayarını false olarak ayarlamayı denemelisiniz. Boş liste ile yaşadığınız sorun, listenin sonunda repsep satır sonu tüketmiyor neden olur. Her öğe sonra Bunun yerine, satır sonu ayrıştırmak gerekir (veya muhtemelen girişin sonuna):

import util.parsing.combinator.RegexParsers 

object WordList extends RegexParsers { 

    private val eoi = """\z""".r // end of input 
    private val eol = sys.props("line.separator") 
    private val separator = eoi | eol 
    private val word = """\w+""".r 

    override val skipWhitespace = false 

    val list: Parser[List[String]] = rep(word <~ separator) 

    val lists: Parser[List[List[String]]] = repsep(list, rep1(eol)) 

    def main(args: Array[String]) { 
    val s = 
     """cat 
     |mouse 
     |horse 
     | 
     |apple 
     |orange 
     |pear""".stripMargin 

    println(parseAll(lists, s)) 
    } 

} 

Sonra tekrar, ayrıştırıcı combinators overkill burada biraz vardır. Pratik olarak aynı şeyi (ancak Listeler yerine Dizilerle) çok daha basit bir şeyle elde edebilirsiniz:

s.split("\n{2,}").map(_.split("\n")) 
+0

Sözcük listeleri arasında yalnızca bir boş satır varsa çalışır. _n_ boş satırlar varsa, ortadaki _n-1_ boş boş listelerle sonuçlanırız. (BTW: 'skipWhitespace' ve eoi' örnekleri çok faydalıdır.) –

+0

@ W.P.McNeill - Dizeleri listeler arasında' rep1 (eol) 'i bulmak için kodu güncelledim. Bunun için mi gidiyordun? – DaoWen

+1

'rep1 (eol)' ben aradığım şey. Teşekkürler. Çözümleyici kombinatorlerin burada çok fazla olduğunu biliyorum. Sorunu açıklamak amacıyla problemi kasıtlı olarak basitleştirdim. –