2009-11-29 8 views
11

मुझे आश्चर्य है कि नीचे वर्णित नियमित मिलान से मेल खाने वाला मिलान प्राप्त करना संभव है या नहीं। निश्चित रूप सेस्केल पार्सर नियमित अभिव्यक्ति मिलान डेटा तक पहुंच

object DateParser extends JavaTokenParsers { 

    .... 

    val dateLiteral = """(\d{4}[-/])?(\d\d[-/])?(\d\d)""".r ^^ { 
     ... get MatchData 
    } 
} 

एक विकल्प ब्लॉक के अंदर फिर से मैच प्रदर्शन करने के लिए है, लेकिन पहले से ही RegexParser मैच मैं आशा करती हूं कि यह ब्लॉक करने के लिए MatchData गुजरता है, या स्टोर यह प्रदर्शन किया है के बाद से?

उत्तर

20

यहाँ निहित परिभाषा है कि आपके Regex एक Parser में धर्मान्तरित है:।

+०१२३५१६४१०६१
/** A parser that matches a regex string */ 
    implicit def regex(r: Regex): Parser[String] = new Parser[String] { 
    def apply(in: Input) = { 
     val source = in.source 
     val offset = in.offset 
     val start = handleWhiteSpace(source, offset) 
     (r findPrefixMatchOf (source.subSequence(start, source.length))) match { 
     case Some(matched) => 
      Success(source.subSequence(start, start + matched.end).toString, 
        in.drop(start + matched.end - offset)) 
     case None => 
      Failure("string matching regex `"+r+"' expected but `"+in.first+"' found", in.drop(start - offset)) 
     } 
    } 
    } 

बस इसे अनुकूलन:

object X extends RegexParsers { 
    /** A parser that matches a regex string and returns the Match */ 
    def regexMatch(r: Regex): Parser[Regex.Match] = new Parser[Regex.Match] { 
    def apply(in: Input) = { 
     val source = in.source 
     val offset = in.offset 
     val start = handleWhiteSpace(source, offset) 
     (r findPrefixMatchOf (source.subSequence(start, source.length))) match { 
     case Some(matched) => 
      Success(matched, 
        in.drop(start + matched.end - offset)) 
     case None => 
      Failure("string matching regex `"+r+"' expected but `"+in.first+"' found", in.drop(start - offset)) 
     } 
    } 
    } 
    val t = regexMatch("""(\d\d)/(\d\d)/(\d\d\d\d)""".r) ^^ { case m => (m.group(1), m.group(2), m.group(3)) } 
} 

उदाहरण:

scala> X.parseAll(X.t, "23/03/1971") 
res8: X.ParseResult[(String, String, String)] = [1.11] parsed: (23,03,1971) 
+0

धन्यवाद डैनियल, एक आकर्षण की तरह काम करता है –

+0

ग्रेट पोस्ट! अति उत्कृष्ट! – fotNelton

+0

यह अजीब बात है, इस तरह की कार्यक्षमता मानक (पुस्तकालय) वर्ग कार्यान्वयन का हिस्सा क्यों नहीं है? यह बहुत उपयोगी दिखता है, लेकिन प्रत्येक उपयोगकर्ता को स्वयं इसे लागू करना चाहिए ... –

1

जब एक Regex एक RegexParsers उदाहरण में प्रयोग किया जाता है, निहित डीईएफ़ regex (Regex): पार्सर [स्ट्रिंग] RegexParsers में कि Regex इनपुट करने के लिए appoly किया जाता है। वर्तमान इनपुट पर आरई के सफल अनुप्रयोग पर प्राप्त मैच उदाहरण का उपयोग रेगेक्स() विधि में सफलता बनाने के लिए किया जाता है, लेकिन केवल इसका "अंत" मान उपयोग किया जाता है, इसलिए किसी भी कब्जे वाले उप-मैचों को उस विधि द्वारा त्याग दिया जाता है रिटर्न।

जैसा कि यह खड़ा है (2.7 स्रोत में मैंने देखा), आप भाग्य से बाहर हैं, मुझे विश्वास है।

3

नहीं, आप यह नहीं कर सकते हैं। जिसका उपयोग आपने एक पार्सर के लिए एक regex परिवर्तित पार्सर की परिभाषा को देखें, तो इसे दूर सभी संदर्भ फेंकता है और अभी पूर्ण मिलान किया स्ट्रिंग रिटर्न:

http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_7_final/src/library/scala/util/parsing/combinator/RegexParsers.scala?view=markup#L55

आप अन्य विकल्पों में से एक जोड़ी है, हालांकि :

  • कई छोटे पारसर्स में अपने पार्सर को तोड़ने (टोकन आप वास्तव में निकालने के लिए चाहते हैं के लिए)
  • कि मूल्यों आप चाहते हैं निकालता है और एक स्ट्रिंग के बजाय एक डोमेन ऑब्जेक्ट एक कस्टम पार्सर परिभाषित

पहले की तरह

val separator = "-" | "/" 
    val year = ("""\d{4}"""r) <~ separator 
    val month = ("""\d\d"""r) <~ separator 
    val day = """\d\d"""r 

    val date = ((year?) ~ (month?) ~ day) map { 
    case year ~ month ~ day => 
     (year.getOrElse("2009"), month.getOrElse("11"), day) 
    } 

<~ साधन लगेगा "इन दो टोकन एक साथ की आवश्यकता होती है, लेकिन केवल मुझे पहले एक का परिणाम दे।

~ का अर्थ है "इन दो टोकन एक साथ की आवश्यकता होती है और उन्हें एक साथ टाई एक पैटर्न-तुलनीय ~ वस्तु।

? मतलब यह है कि पार्सर वैकल्पिक है और एक विकल्प वापस आ जाएगी।

.getOrElse बिट में जब पार्सर एक मूल्य को परिभाषित नहीं किया लिए एक डिफ़ॉल्ट मान प्रदान करता है

+0

धन्यवाद डेविड, अच्छा: RegexParsers वर्ग का उपयोग कर "नाम मूल्य" उपाय। मैं कस्टम पार्सर समाधान के साथ जा रहा हूं क्योंकि यह व्याकरण परिभाषा को अधिक पठनीय रखता है। –

+1

अब जब मैं इसके बारे में सोचता हूं, एक कस्टम पार्सर भी अधिक सही है। प्रत्येक व्यक्तिगत रेगेक्स पार्सर अग्रणी व्हाइटस्पेस की अनुमति देता है, इसलिए मैंने जो कोड पोस्ट किया है वह "1999 - 02 - 28" जैसे स्ट्रिंग से मेल खाता है। –

0

मैं ने वही समस्या स्केला 2.8 का उपयोग कर में फंस गयी।1 और प्रपत्र के इनपुट पार्स करने का प्रयास

package scalucene.query 

import scala.util.matching.Regex 
import scala.util.parsing.combinator._ 

object QueryParser extends RegexParsers { 
    override def skipWhitespace = false 

    private def quoted = regex(new Regex("\"[^\"]+")) 
    private def colon = regex(new Regex(":")) 
    private def word = regex(new Regex("\\w+")) 
    private def fielded = (regex(new Regex("[^:]+")) <~ colon) ~ word 
    private def term = (fielded | word | quoted) 

    def parseItem(str: String) = parse(term, str) 
} 

ऐसा लगता है कि आप इस तरह से पार्स करने के बाद मिलान किया समूहों हड़पने कर सकते हैं::

QueryParser.parseItem("nameExample:valueExample") match { 
    case QueryParser.Success(result:scala.util.parsing.combinator.Parsers$$tilde, _) => { 
     println("Name: " + result.productElement(0) + " value: " + result.productElement(1)) 
    } 
}