需要帮助修改正则表达式

时间:2010-08-22 06:15:20

标签: java regex

有一天我会擅长正则表达式,但现在......

我正在解析使用以下表达式查找MP3文件的HTML页面(可以正常工作):

"<A HREF=\"([^\"]+)\"[^>]*>([^<]+?)\\.mp3</A>"

我现在想要搜索MP3和OGG文件。看起来像一个简单的OR修改(.mp3 || .ogg),但我不太确定我是怎么把它放在那里的?有关详细信息,请参阅Trying to parse links in an HTML directory listing using Java regex

2 个答案:

答案 0 :(得分:5)

了解模式

您有以下Java字符串文字:

// Java string literal
"<A HREF=\"([^\"]+)\"[^>]*>([^<]+?)\\.mp3</A>"

当处理所有转义序列时,此字符串表示的模式为:

// the regex pattern
<A HREF="([^"]+)"[^>]*>([^<]+?)\.mp3</A>

现在让我们分开这个模式:

_________       _     _        E________
<A HREF="([^"]+)"[^>]*>([^<]+?)\.mp3</A>
         \_____/       \______/
            1              2

所以这个正则表达式的部分是:

  1. <A HREF="字面匹配
  2. ([^"]+),即除了双引号之外的所有内容,在第1组中捕获
  3. "字面意思
  4. [^>]*,即>
  5. 以外的所有内容
  6. >字面匹配
  7. ([^<]+?),即第2组中捕获的尽可能少的<以外的所有内容
  8. .mp3</A>字面匹配(.通过反斜杠进行转义)
  9. 所以看看这个,我们可以观察到正则表达式做出以下假设:

    • href属性值与第2部分匹配;它必须用双引号括起来,并且本身不能包含任何转义的双引号。此匹配将捕获到组1中。
    • 任何剩余的属性都与第4部分匹配。href必须是第一个属性,否则正则表达式将不匹配。
    • 第6部分匹配文件名,捕获到第2组。
    • 第7部分匹配扩展名,并紧接在结束元素之后。第6部分的不情愿可能没有必要。

    使用正则表达式解析HTML是一件棘手的事情,但是考虑到许多假设,上述正则表达式似乎能够在大多数时间内完成工作。


    修改模式

    正则表达式中的

    Alternation是使用垂直条完成的。了解其优先级以及分组如何有用非常重要。

    • this|that匹配以下两个字符串中的一个:
      • "this"
      • "that"
    • this|that thing匹配以下两个字符串中的一个:
      • "this"
      • "that thing"
    • (this|that) thing匹配以下两个字符串中的一个:
      • "this thing"
      • "that thing"
    • (this|that) (thing|stuff)匹配以下四个字符串中的一个:
      • "this thing"
      • "that thing"
      • "this stuff"
      • "that stuff"

    为了同时允许mp3ogg扩展,我们可以将模式中的mp3修改为(mp3|ogg)。请注意,此组将匹配并将扩展名捕获到组3中。

    因此,最终模式是:

    <A HREF="([^"]+)"[^>]*>([^<]+)\.(mp3|ogg)</A>
             \_____/       \_____/  \_______/
              1:url      2:filename   3:ext
    

    作为Java字符串文字,这是:

    "<A HREF=\"([^\"]+)\"[^>]*>([^<]+)\\.(mp3|ogg)</A>"
    

    附录

    […]character class。像[aeiou]这样的东西匹配任何一个小写元音。 [^…]否定的字符类。 [^aeiou]除了小写元音之外的任何内容匹配。

    (…)capturing group。它允许稍后检索匹配的字符串。

    *+repetition specifiers。默认情况下,重复是贪婪的(即尽可能匹配)。 ?中的+?使其不情愿(即匹配为少数)。

    请注意,?在其他情境中也可能充当optional repetition specifier

    .matches (almost) any character的元字符。由于我们需要一个文字句号,我们通过前面的双打来逃避它。

    请注意,正则表达式模式默认区分大小写。在Java中,您可能希望在模式中使用Pattern.CASE_INSENSITIVE标志(可嵌入为(?i))。

答案 1 :(得分:4)

Replace 
    \.mp3
with
    \.((mp3)|(ogg))

请注意使用正则表达式解析HTML。