簡體   English   中英

組數可變的正則表達式?

[英]Regular expression with variable number of groups?

是否可以創建具有可變數量組的正則表達式?

例如運行這個之后......

Pattern p = Pattern.compile("ab([cd])*ef");
Matcher m = p.matcher("abcddcef");
m.matches();

...我想要類似的東西

  • m.group(1) = "c"
  • m.group(2) = "d"
  • m.group(3) = "d"
  • m.group(4) = "c"

(背景:我正在解析一些數據行,其中一個“字段”在重復。我想避免對這些字段使用matcher.find循環。)


正如@Tim Pietzcker 在評論中指出的那樣, perl6.NET具有此功能。

根據文檔,Java 正則表達式不能這樣做:

與組關聯的捕獲輸入始終是該組最近匹配的子序列。 如果由於量化而對組進行第二次評估,那么如果第二次評估失敗,則將保留其先前捕獲的值(如果有)。 例如,將字符串“aba”與表達式 (a(b)?)+ 匹配,將第二組設置為“b”。 在每次匹配開始時,所有捕獲的輸入都將被丟棄。

(強調)

您可以使用 split 將您需要的字段放入數組並循環遍歷。

http://download.oracle.com/javase/1,5.0/docs/api/java/lang/String.html#split(java.lang.String )

我沒有使用過 java regex,但對於許多語言,答案是:不。

捕獲組似乎在解析正則表達式時創建,並在匹配字符串時填充。 表達式(a)|(b)(c)具有三個捕獲組,前提是可以填充其中一個或兩個。 (a)*只有一個組,解析器匹配后留下組中的最后一個匹配項。

Pattern p = Pattern.compile("ab(?:(c)|(d))*ef");
Matcher m = p.matcher("abcdef");
m.matches();

應該做你想做的。

編輯:

@aioobe,我現在明白了。 你希望能夠做一些類似語法的事情

A    ::== <Foo> <Bars> <Baz>
Foo  ::== "foo"
Baz  ::== "baz"
Bars ::== <Bar> <Bars>
        | ε
Bar  ::== "A"
        | "B"

並拉出Bar所有個人匹配項。

不,沒有辦法使用java.util.regex做到這一點。 您可以遞歸並在Bars的匹配上使用正則表達式,或者使用像 ANTLR 這樣的解析器生成器並將副作用附加到Bar

我剛剛遇到了非常相似的問題,並設法做到了“可變數量的組”,但結合了 while 循環和重置匹配器。

    int i=0;
    String m1=null, m2=null;

    while(matcher.find(i) && (m1=matcher.group(1))!=null && (m2=matcher.group(2))!=null)
    {
        // do work on two found groups
        i=matcher.end();
    }

但這是針對我的問題(有兩個重復

    Pattern pattern = Pattern.compile("(?<=^ab[cd]{0,100})[cd](?=[cd]{0,100}ef$)");
    Matcher matcher = pattern.matcher("abcddcef")
    int i=0;
    String res=null;

    while(matcher.find(i) && (res=matcher.group())!=null)
    {
        System.out.println(res);
        i=matcher.end();
    }

您無法使用*+指定任意長度的重復,因為前瞻和后視必須具有可預測的長度。

我認為回溯會抑制這種行為,並說/([\\S\\s])/在其分組累積狀態下對聖經之類的東西的影響。 即使可以完成,輸出也是不可知的,因為組將失去位置意義。 最好在全局意義上對同類進行單獨的正則表達式並將其存放到數組中。

如果有合理的最大匹配組數,您會遇到:

"ab([cd])?([cd])?([cd])?([cd])?([cd])?([cd])?([cd])?([cd])?ef"

此示例適用於 0 - 8 個匹配項。 我承認這很丑陋,而且不是人類可讀的。

我想避免對這些字段使用 matcher.find 循環。

正如其他答案中所述,這是無法避免的。 為了完整起見,這里是如何使用第二個Pattern到 go 來完成各個匹配項。 請注意*的 position 在圓括號內而不是之后。

Pattern subPattern = Pattern.compile("[cd]");
Pattern pattern = Pattern.compile("ab(" + subPattern.pattern() + "*)ef"); // DRY, but probably safer ways to do it for the case that subPattern needs to be changed.
Matcher matcher = pattern.matcher("abccdcddef is great and all, but have you heard about abef and abddcef?");
List<String> letterSequence = new ArrayList<>();
while (matcher.find()) {
    String letters = matcher.group(1);
    Matcher subMatcher = subPattern.matcher(letters);
    while (subMatcher.find()) {
        String letter = subMatcher.group();
        letterSequence.add(letter);
    }
}
System.out.println(letterSequence);

Output:

[c, c, d, c, d, d, d, d, c]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM