2012-04-04 5 views
8

मान लें कि मैं विभिन्न खोलने और समापन ब्रैकेट के साथ एक स्ट्रिंग को पार्स करना चाहता हूं (मैंने शीर्षक में ब्रांड्स का उपयोग किया क्योंकि मुझे लगता है कि यह अधिक आम है - सवाल फिर भी वही है) कि मुझे एक सूची में अलग सभी उच्च स्तर मिलते हैं।स्कैला में मिलान करने वाले अभिभावक --- कार्यात्मक दृष्टिकोण

को देखते हुए:

[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]] 

मैं चाहता हूँ:

List("[hello:=[notting],[hill]]", "[3.4(4.56676|5.67787)]", "[the[hill[is[high]]not]]") 

तरह से मैं यह कर रहा हूं उद्घाटन गिनती और कोष्ठक बंद करने और सूची में जोड़ने से जब भी मैं 0 करने के लिए अपने काउंटर प्राप्त कर रहा है। हालांकि, मेरे पास एक बदसूरत अनिवार्य कोड है। आप मान सकते हैं कि मूल स्ट्रिंग अच्छी तरह से बनाई गई है।

मेरा प्रश्न है: इस समस्या के लिए एक अच्छा कार्यात्मक दृष्टिकोण क्या होगा?

नोट्स: मैंने इसका उपयोग करने के बारे में सोचा है ... उपज निर्माण लेकिन काउंटरों के उपयोग को देखते हुए मुझे एक साधारण सशर्त नहीं मिल सकता है (मुझे केवल काउंटर अपडेट करने के लिए सशर्त होना चाहिए) और मुझे नहीं पता कि कैसे मैं इस मामले में इस निर्माण का उपयोग कर सकता था।

+0

देखें "पार्सर combinators": http://stackoverflow.com/search?q = स्कैला + पार्सर + संयोजक –

+1

इसी तरह का मामला: http://blog.tmorris.net/haskell-scala-java-7- कार्यात्मक-java-java/। टिप्पणियों में कोड सबसे उपयोगी बिट है। –

+0

@AlexanderAzarov, हर बार जब मैं पार्सर संयोजकों के साथ खेलता हूं, मुझे लगता है कि मुझे लगभग निश्चित समय में समाधान प्राप्त करने के लिए कुशल होने के लिए इसके साथ अधिक अनुभव की आवश्यकता होगी। क्या यह यहाँ अधिक है? – huynhjl

उत्तर

7

त्वरित समाधान का उपयोग कर स्काला पार्सर Combinator पुस्तकालय:

import util.parsing.combinator.RegexParsers 

object Parser extends RegexParsers { 
    lazy val t = "[^\\[\\]\\(\\)]+".r 

    def paren: Parser[String] = 
    ("(" ~ rep1(t | paren) ~ ")" | 
    "[" ~ rep1(t | paren) ~ "]") ^^ { 
     case o ~ l ~ c => (o :: l ::: c :: Nil) mkString "" 
    } 

    def all = rep(paren) 

    def apply(s: String) = parseAll(all, s) 
} 

आरईपीएल में यह जांच की जा रही:

scala> Parser("[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]") 
res0: Parser.ParseResult[List[String]] = [1.72] parsed: List([hello:=[notting],[hill]], [3.4(4.56676|5.67787)], [the[hill[is[high]]not]]) 
+0

ऐसा करने पर यह इतना आसान लगता है। मैंने इस पर कुल मिलाकर कुछ घंटों की तरह बिताई है और जो मैंने किया था वह उतना ही कम था: '"[" ~ rep (paren ~ opt (t)) ~ "]" | "[" ~ प्रतिनिधि (टी ~ ऑप्ट (पैरेंट)) ~ "]" '। – huynhjl

0

इस प्रयास करें:

val s = "[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]" 
s.split("]\\[").toList 

रिटर्न:

List[String](
    [hello:=[notting],[hill], 
    3.4(4.56676|5.67787), 
    the[hill[is[high]]not]] 
) 
+0

इस उदाहरण को देखें: "[एफ [उदास] [add] dir] [er] [p]"। आपने जो सुझाव दिया है वह सामान्य मामले को हल नहीं करता है। इसके अलावा, मैं एक त्वरित फिक्स की तलाश नहीं कर रहा हूं, मेरे पास एक पूरी तरह से काम कर रहा कोड है। – PhyBandit

+0

आपूर्ति किए गए विशिष्ट मामले पर परिचालन कर रहा था। @ hyunhjl का जवाब विशेष रूप से दिलचस्प है ... – virtualeyes

4

के बारे में क्या:

def split(input: String): List[String] = { 
    def loop(pos: Int, ends: List[Int], xs: List[String]): List[String] = 
    if (pos >= 0) 
     if ((input charAt pos) == ']') loop(pos-1, pos+1 :: ends, xs) 
     else if ((input charAt pos) == '[') 
     if (ends.size == 1) loop(pos-1, Nil, input.substring(pos, ends.head) :: xs) 
     else loop(pos-1, ends.tail, xs) 
     else loop(pos-1, ends, xs) 
    else xs 
    loop(input.length-1, Nil, Nil) 
} 

scala> val s1 = "[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]" 
s1: String = [hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]] 

scala> val s2 = "[f[sad][add]dir][er][p]" 
s2: String = [f[sad][add]dir][er][p] 

scala> split(s1) foreach println 
[hello:=[notting],[hill]] 
[3.4(4.56676|5.67787)] 
[the[hill[is[high]]not]] 

scala> split(s2) foreach println 
[f[sad][add]dir] 
[er] 
[p] 
+0

+1, मेरा उत्तर विशिष्ट मामले पर आधारित था, न कि जेनेरिक, जिसे स्पष्ट रूप से अधिक जटिल, और स्पष्ट रूप से पुनरावृत्त, समाधान की आवश्यकता होती है। – virtualeyes

2

अपनी आवश्यकताओं को देखते हुए कोष्टक गिनती बिल्कुल ठीक लगता है। आप इसे एक कार्यात्मक तरीके से कैसे करेंगे? आप राज्य को स्पष्ट रूप से पारित कर सकते हैं।

case class Parsed(blocks: Vector[String], block: String, depth: Int) 

फिर हम एक शुद्ध समारोह है कि संसाधित है कि अगले राज्य रिटर्न लिखें:

तो सबसे पहले हम अपने राज्य में जो blocks में परिणाम जम जाता है या अगले block संयोजित और गहराई का ट्रैक रखता है परिभाषित करते हैं। उम्मीद है कि, हम केवल इस कार्य को ध्यान से देख सकते हैं और यह सुनिश्चित कर सकते हैं कि यह सही है।

def nextChar(parsed: Parsed, c: Char): Parsed = { 
    import parsed._ 
    c match { 
    case '[' | '(' => parsed.copy(block = block + c, 
            depth = depth + 1) 
    case ']' | ')' if depth == 1 
        => parsed.copy(blocks = blocks :+ (block + c), 
            block = "", 
            depth = depth - 1) 
    case ']' | ')' => parsed.copy(block = block + c, 
            depth = depth - 1) 
    case _   => parsed.copy(block = block + c) 
    } 
} 

तो हम सिर्फ एक foldLeft इस्तेमाल किया एक प्रारंभिक राज्य के साथ डेटा की प्रक्रिया करने के लिए:

val data = "[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]" 
val parsed = data.foldLeft(Parsed(Vector(), "", 0))(nextChar) 
parsed.blocks foreach println 

कौन देता है:

[hello:=[notting],[hill]] 
[3.4(4.56676|5.67787)] 
[the[hill[is[high]]not]] 
+0

दमित, मेरे पास अभी भी वही विचार था। – Debilski

2

आप एक बदसूरत जरूरी समाधान है, तो क्यों नहीं एक अच्छा दिखने वाला एक? :)

यह हुंहजल के समाधान का एक अनिवार्य अनुवाद है, लेकिन यह दिखाने के लिए पोस्ट करना कि कभी-कभी अनिवार्य संक्षिप्त और शायद पालन करना आसान होता है।

def parse(s: String) = { 
    var res = Vector[String]() 
    var depth = 0 
    var block = "" 
    for (c <- s) { 
     block += c 
     c match { 
     case '[' => depth += 1 
     case ']' => depth -= 1 
        if (depth == 0) { 
         res :+= block 
         block = "" 
        } 
     case _ => 
     } 
    } 
    res 
    } 
संबंधित मुद्दे