2012-12-11 114 views
6

在Ruby中,如果我有兩個正則表達式,我要創建另一個正則表達式這樣的可能性:斯卡拉正則表達式工會

a = /\d+/ # Matches digits 
b = /\s+/ # Matches whitespaces 
c = Regexp.union(a, b) # Matches sequences that consist only of digits or only of whitespaces 

我想要做的斯卡拉同樣的事情,但我沒找到我怎麼能做到這一點。請注意,我沒有要求在前面的示例中創建像(\d+)|(\s+)這樣的字符類的聯合的語法,我真的正在尋找從兩個給定的Regexps創建新的Regexp的可能性。

實際上,最後我不會爲兩個正則表達式做它,而是大量的。我不在乎分組或任何東西,我只想知道一個字符串是否與給定正則表達式列表中的某一個匹配。我可以在一個循環中檢查它們,但是效率太低,這就是爲什麼我需要一個Regexp來檢查聯合。

+1

如果要匹配* this *或* that *,則必須使用Alternation'|'。 – stema

+1

如果在Scala中不存在'類似於聯合體的方法,則可以檢索每個正則表達式使用的模式,然後像'(regex1)|(regex2)'手動合併它們,並從結果中創建一個新的正則表達式。 – Vulcan

+0

@stema是的,我知道,如果我創建正則表達式,那麼我使用|,但如果我已經給了兩個正則表達式,並且我想將它們合併,我需要其他東西。 – Lykos

回答

7

Scala使用基於類java.util.regex.Pattern的Java正則表達式引擎。 Pattern有且只有一個方法,它可以創建一個正則表達式:

public static Pattern compile(String regex) 

就是這樣,和Scala不給你任何相關的改進。

但有一兩件事你可以做的是使用內置的匹配語句,在情況捕獲組此處顯示unioning你想拉出來的東西的字符串:

val Dig = """(\d+)""".r 
val Wsp = """(\s+)""".r 

scala> "45" match { case Dig(_) | Wsp(_) => println("found"); case _ => } 

發現

scala> " " match { case Dig(_) | Wsp(_) => println("found"); case _ => } 

found

如果你真的想要一個組合的正則表達式,你必須在字符串級別。您可以從.pattern從Scala正則表達式獲得java Pattern,然後另一個.pattern獲取該字符串。大多數正則表達式可以安全地(?:)包裹得到一個非獲取塊,這樣你就可以結合像這樣:

val Both = ("(?:"+Dig.pattern.pattern+")|(?:"+Wsp.pattern.pattern+")").r 

然而,任何捕獲組內將來表示,但不使用的分行將是null(不完全寫成語斯卡拉的好方法,但無論如何,這是Java使用):

scala> "2" match { case Both(d,w) => if (w!=null) println("white") else println(d) } 
2 

scala> " " match { case Both(d,w) => if (w!=null) println("white") else println(d) } 
white 
+0

謝謝,與Dig(_)|的版本Wsp(_)實際上並不適用於我的應用程序,這些只是示例,在我的實際應用程序中,我有很長的Regexps列表,因此使用多個模式效率不高。我想我可能會用你的第二個解決方案來做,我只希望有一些不像我的Ruby例子那麼糟糕。 – Lykos

+2

@Lykos - 你總是可以寫出一種將對或序列放在一起的方法。例如,如果'xs'是一個正則表達式集合,'xs.map(_。pattern.pattern).mkString(「(?:」,「)|(?:」,「)」)。r'應該是他們整個羣體的正則表達式 –

+0

是的,謝謝,實際上,這就是我所做的。^^ – Lykos

1

如果要合併和重用正則表達式的部分,我寫了REL庫/ DSL,不只是那。用法示例爲您的情況:

import fr.splayce.rel._ 
import Implicits._ 

val a: RE = "\\d+" 
val b: RE = "\\s+" 
val c: RE = a | b 

cr方法得到一個正則表達式對象。它也在Implicits,所以你可以使用它作爲一個正則表達式,說c findAllIn someText。如果需要,它會自動將ab包裝在非捕獲組中。

如果你有正則表達式的集合,你可以做reduceLeft

val regexes: List[RE] = List("a", "b", "c") 
regexes.reduceLeft(_ | _) 

在一個側面說明:

  • 如果導入Symbols._,你有東西像\d和短符號\s
  • 它實現了大部分通常的正則表達式操作以獲得最大的可重用性

因此,REL,您可以直接寫第一個例子是:

val c = δ.+ | σ.+ 

它還提供了一些方法重用,並結合相關的提取。

如果你喜歡香草Scala,那麼我沒有什麼可以添加到雷克斯克爾的答案。

+0

謝謝,你的圖書館看起來不錯。然而,如果我只在一個位置使用它,我總是有點不情願爲另一個庫添加一個新的依賴項,所以我遵循另一個方法。 – Lykos

+1

我明白了,這就是我的立場。我主要將這個答案留給可能需要更完整解決方案的其他讀者。 –

1

儘管這些答案可能有效,但它們可能有些過時或過於複雜。如果你想正則表達式的列表

val reg1 = "\\d+".r 
val reg2 = "\\s+".r 
val reg3 = s"${reg1}{$reg2}".r 
"123 " match { 
    case reg3(_*) => println("match") 
    case _ => println("no match") 
} 
+0

感謝您的更新。 :) – Lykos

+0

您的代碼不回答當前問題:「我只想知道一個字符串是否與給定的正則表達式列表中的一個匹配」 – akauppi

0

@akauppi匹配一個給定的字符串,你可以做這樣的事情:

val regexes = List("\\d+".r, "\\s+".r, "a".r) 
val single = s"(${regexes.mkString("|")})".r 
"123" match { 
    case single(_*) = println("match") 
    case _ => println("no match") 
} 
// above prints: match 

"123 " match { 
    case single(_*) = println("match") 
    case _ => println("no match") 
} 
// above prints: no match 

利用正則表達式的列表,最好的辦法是使用正則表達式表示法。這與說法相同

val single = "(\\d+|\\s+|a)".r