【问题标题】:Parsing HLS m3u8 file using regular expressions使用正则表达式解析 HLS m3u8 文件
【发布时间】:2013-03-07 07:54:54
【问题描述】:

我想解析 HLS 主 m3u8 文件并从中获取带宽、分辨率和文件名。目前我正在使用字符串解析来搜索字符串以查找某些模式并执行子字符串以获取值。

示例文件:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=476416,RESOLUTION=416x234
Stream1/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=763319,RESOLUTION=480x270
Stream2/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1050224,RESOLUTION=640x360
Stream3/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1910937,RESOLUTION=640x360
Stream4/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3775816,RESOLUTION=1280x720
Stream5/index.m3u8

但我发现我们可以使用这个问题中提到的正则表达式来解析它: Problem matching regex pattern in Android

我对正则表达式没有任何想法,所以请有人指导我使用正则表达式解析它。

或者有人可以帮助我编写正则表达式以从下面的字符串中解析出 BANDWIDTH 和 RESOLUTION 值

#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=476416,RESOLUTION=416x234

【问题讨论】:

    标签: android regex http-live-streaming m3u8


    【解决方案1】:

    你可以试试这样的:

        final Pattern pattern = Pattern.compile("^#EXT-X-STREAM-INF:.*BANDWIDTH=(\\d+).*RESOLUTION=([\\dx]+).*");
    
        Matcher matcher = pattern.matcher("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=476416,RESOLUTION=416x234");
        String bandwidth = "";
        String resolution = "";
    
        if (matcher.find()) {
            bandwidth = matcher.group(1);
            resolution = matcher.group(2);
        }
    

    将带宽和分辨率设置为正确的(字符串)值。

    我没有在安卓设备或模拟器上试过这个,但是从你发送的链接和安卓 API 来看,它应该和上面的普通 java 一样工作。

    正则表达式匹配以#EXT-X-STREAM-INF: 开头并包含BANDWIDTHRESOLUTION 后跟正确值格式的字符串。然后这些在反向引用组 1 和 2 中被反向引用,以便我们可以提取它们。

    编辑:

    如果 RESOLUTION 并不总是存在,那么您可以将该部分设为可选:

    "^#EXT-X-STREAM-INF:.*BANDWIDTH=(\\d+).*(?:RESOLUTION=([\\dx]+))?.*"
    

    如果只存在BANDWIDTH,则resolution 字符串将为null

    编辑2:

    ? 使事情成为可选的,(?:___) 表示被动组(而不是反向引用组(___)。所以它基本上是一个可选的被动组。所以是的,它里面的任何东西都是可选的。

    . 匹配单个字符,* 表示它将重复零次或多次。所以.* 将匹配零个或多个字符。我们需要这个的原因是消耗我们匹配的东西之间的任何东西,例如#EXT-X-STREAM-INF:BANDWIDTH 之间的任何内容。有很多方法可以做到这一点,但.* 是最通用/最广泛的一种。

    \d 基本上是一组表示数字的字符(0-9),但是由于我们将字符串定义为 Java 字符串,所以我们需要双精度 \\,否则 Java 编译器会失败,因为它没有识别转义字符 \d(在 Java 中)。相反,它会将\\ 解析为\,以便我们在传递给Pattern 构造函数的最终字符串中获得\d

    [\dx]+ 表示字符 0-9x 中的一个或多个字符 (+)。 [\dx\d] 将是同一组字符中的单个字符(不是 +)。

    如果您对正则表达式感兴趣,可以查看regular-expressions.info 或/和regexone.com,在那里您会找到所有问题的更深入的答案。

    【讨论】:

    • 感谢您的回复将尝试您的代码。当我们调用pattern.matcher 时,我对模式匹配有疑问,它在matcher 中究竟返回了什么,是在正则表达式中省略给定模式的字符串吗?在做了pattern.matcher之后为什么我们打电话给find
    • 匹配器是一个对象,用于根据模式对给定字符串执行匹配操作。当您调用find() 时,它会尝试在给定字符串中查找下一个匹配项,如果找到,则返回 true,我们可以提取结果。您可以查看the documentation 以获取更多信息(即 Java 文档,但它在 Android 上的行为方式应该相同,android 文档中没有太多详细信息)。
    • 感谢您的解释!我绑定了您的代码,它正在工作,但是如果字符串中没有 RESOLUTION 而只有带宽呢?我试过了,但find 在这种情况下失败了。是否有可能在任何一种情况下检查 RESOLUTION 如果找到然后 ok 否则只是忽略或者我们是否需要有两个单独的表达式来解析带宽和分辨率并将相同的字符串传递给它们并调用 find?
    • 查看我的编辑 :) 只要只有 RESOLUTION 是可选的,它就是直截了当的,如果你有没有 BANDWIDTH 但有 RESOLUTION 的实例,那么它会变得有点棘手,但它仍然应该是可行的。
    • 更新了我的答案以包含您的最新问题。
    【解决方案2】:

    你可以只拆分字符串,这就是我在 python 中的意思。

    fu ="#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=476416,RESOLUTION=416x234"
    
    for chunk in fu.split(':')[1].split(','):
        if chunk.startswith('BANDWIDTH'):
            bandwidth = int(chunk.split('=')[1])
        if chunk.startswith('RESOLUTION'):
            resolution = chunk.split('=')[1]
    

    【讨论】:

      【解决方案3】:

      我发现这个可能会有所帮助。
      http://sourceforge.net/projects/m3u8parser/
      (许可证:LGPLv3)

      【讨论】:

        【解决方案4】:

        您也可以使用:Python m3u8 parser.

        下面的例子:

        import m3u8
        
        playlist = """
        #EXTM3U
        #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=476416,RESOLUTION=416x234
        Stream1/index.m3u8
        #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=763319,RESOLUTION=480x270
        Stream2/index.m3u8
        #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1050224,RESOLUTION=640x360
        Stream3/index.m3u8
        #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1910937,RESOLUTION=640x360
        Stream4/index.m3u8
        #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3775816,RESOLUTION=1280x720
        Stream5/index.m3u8
        """
        _playlist = m3u8.loads(playlist).playlists
        
        for item in _playlist:
            item_uri   = item.uri 
            resolution = item.stream_info.resolution
            bandwidth  = item.stream_info.bandwidth
            print(item_uri ,resolution , bandwidth )
        

        结果将是:

        Stream1/index.m3u8 (416, 234) 476416
        Stream2/index.m3u8 (480, 270) 763319
        Stream3/index.m3u8 (640, 360) 1050224
        Stream4/index.m3u8 (640, 360) 1910937
        Stream5/index.m3u8 (1280, 720) 3775816
        

        【讨论】:

          猜你喜欢
          • 2018-04-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-07
          • 1970-01-01
          相关资源
          最近更新 更多