2009-07-06 10 views
20

Uczę się Scala, więc prawdopodobnie jest to dość noob-irific.Scala Regex włącz opcję Multiline

Chcę mieć wyrażenie regularne wieloliniowe.

W Ruby byłoby:

MY_REGEX = /com:Node/m 

Moja Scala wygląda następująco:

val ScriptNode = new Regex("""<com:Node>""") 

Oto mój mecz funkcja:

def matchNode(value : String) : Boolean = value match 
{ 
    case ScriptNode() => System.out.println("found" + value); true 
    case _ => System.out.println("not found: " + value) ; false 
} 

A ja nazywając go tak:

matchNode("<root>\n<com:Node>\n</root>") // doesn't work 
matchNode("<com:Node>") // works 

Próbowałem:

val ScriptNode = new Regex("""<com:Node>?m""") 

A ja naprawdę chciałbym uniknąć konieczności korzystania java.util.regex.Pattern. Wszelkie wskazówki bardzo doceniane.

+0

okrzyki za formatowanie! nie działa dla mnie –

+1

Musisz zostawić pustą linię powyżej i poniżej każdego bloku kodu. –

Odpowiedz

36

Jest to bardzo częsty problem przy pierwszym użyciu Scala Regex.

Kiedy używasz dopasowywania wzorca w Scali, próbuje dopasować cały ciąg, tak jakbyś używał "^" i "$" (i nie aktywował wieloliniowego parsowania, który dopasowuje \ n do^i $).

Sposobem na to, co chcesz byłaby jedną z następujących czynności:

def matchNode(value : String) : Boolean = 
    (ScriptNode findFirstIn value) match {  
    case Some(v) => println("found" + v); true  
    case None => println("not found: " + value) ; false 
    } 

Który znalazłby znaleźć pierwsze wystąpienie scriptNode wewnętrzną wartość i powrócić że instancji jako v (jeśli chcesz cały ciąg, wystarczy wydrukować wartość). Lub:

val ScriptNode = new Regex("""(?s).*<com:Node>.*""") 
def matchNode(value : String) : Boolean = 
    value match {  
    case ScriptNode() => println("found" + value); true  
    case _ => println("not found: " + value) ; false 
    } 

Który wydrukowałby całą wartość. W tym przykładzie (? S) aktywuje dopasowanie punktowe (tj. Dopasowanie "." Do nowych linii), a. * Przed i po szukanym wzorze zapewnia, że ​​będzie dopasowany do dowolnego ciągu. Jeśli chciał „v”, jak w pierwszym przykładzie, można to zrobić:

val ScriptNode = new Regex("""(?s).*(<com:Node>).*""") 
def matchNode(value : String) : Boolean = 
    value match {  
    case ScriptNode(v) => println("found" + v); true  
    case _ => println("not found: " + value) ; false 
    } 
+1

Cudowne rzeczy. Twoje zdrowie! –

+21

Dla czytelników takich jak ja może nie być oczywiste, ale włączenie '(? S)' jest kluczowe tutaj w odniesieniu do dopasowywania do ciągów wieloliniowych. Zobacz http://download.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html#DOTALL – Synesso

+4

@Synesso Twój link jest zepsuty. tutaj jest odpowiednik java 7 http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#DOTALL – harschware

5

tylko szybki i brudny Uzupełnienie: metoda .r na RichString konwertuje wszystkie sznurki do scala.util.matching.Regex, więc można zrobić coś takiego:

"""(?s)a.*b""".r replaceAllIn ("a\nb\nc\n", "A\nB") 

i że wróci

A 
B 
c 

używam tego cały czas, aby w szybki i brudny regex-skryptów w con scala podeszwa.

lub w tym przypadku:

def matchNode(value : String) : Boolean = { 

    """(?s).*(<com:Node>).*""".r.findAllIn(text) match { 

     case ScriptNode(v) => System.out.println("found" + v); true  

     case _ => System.out.println("not found: " + value) ; false 
    } 
} 

Tylko moja próba zmniejszenia użycia słowa new w kodzie na całym świecie.;)

3

Wystarczy niewielki dodatek, korzystanie próbował użyć flagi na (?m) (multiline) (chociaż może nie nadawać się tutaj), ale tutaj jest właściwy sposób z niego korzystać:

np zamiast

val ScriptNode = new Regex("""<com:Node>?m""") 

użycie

val ScriptNode = new Regex("""(?m)<com:Node>""") 

Ale znowu (? s) flaga jest bardziej odpowiedni w tej kwestii (dodanie tej odpowiedzi tylko dlatego, że tytuł jest "Scala Regex włączyć opcję multiline")