作者:Confach 发表于April 23,2006 15:02 pm
版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息.
http://www.cnblogs.com/confach/articles/387902.html


5

第5章 支持的媒体内容(Media Content)

PME内容

播放媒体内容

监听媒体内容事件

创建定制的连接

PME内容

BlackBerry设备支持PME格式的富(rich)媒体内容。

开发者可以使用Plazmic Content Developer’s Kit for BlackBerry来创建PME内容。这个工具,以及附带的文档可以在Plazmic网站(www.plazmic.com)找到。

Media Engine API(在net.rim.plazmic.mediaengine 和 net.rim.plazmic.mediaengine.io包中)允许应用程序获取和播放存储在BlackBerry设备上或网络上的PME内容.
Media Engine API支持媒体格式application/x-vnd.rim.pme. Web服务器必须为application/x-vnd.rim.pme设置MIME类型。

PME API概览

下面3个主要类(在net.rim.plazmic.mediaengine包里)提供了加载和播放PME媒体内容的能力。

描述

MediaManager

提供从本地或网络上加载媒体内容的方法。

MediaPlayer

提供播放PME媒体的方法。

MediaException

为获取或播放媒体的错误提供异常代码。

媒体加载

Media Engine API允许应用程序使用下面4种协议种的一种加载媒体内容:

协议

描述

http://

http协议从一个使用HTTP连接网络Web服务器下载内容。这个协议需要一个带有BlackBerry MDS服务的BES(BlackBerry Enterprise Server,BlackBerry企业服务器).

https://

https协议从一个使用HTTPS连接网络Web服务器下载内容。这个协议需要一个带有BlackBerry MDS服务的BES(BlackBerry Enterprise Server,BlackBerry企业服务器).

Jar:///<pme_file>

jar协议加载存储在本地BlackBerry设备上的jar文件。

jar:///sample.pme

注意:开始的斜线(/)是需要的。

在BlackBerry IDE中,.jar文件必须加入到调用应用程序或应用程序依赖的库的相同项目中。

cod://<module><pme_file>

cod协议加载存储在本地BlackBerry设备上的cod文件。

cod://mediasample/sample.pme

为使用其他协议,实现定制的Connector。为获得更多信息,参看91页的“创建定制的Connector”.

播放状态(Playback states

为了获取MediaPlayer的当前状态,调用MediaPlayer.getState().

状态

描述

UNREALIZED

MediaPlayer未准备播放媒体。为了转到REALIZED状态,调用MediaPlayer.setMedia().

REALIZED

MediaPlayer准备好播放媒体。为了开始播放,并转到STARTED状态,调用MediaPlayer.start().

STARTED

MediaPlayer正在播放媒体。为了停止播放和返回到REALIZED状态,调用MediaPlayer.stop().

异常

MediaEngine和MediaManager类的方法抛出一个MediaException异常,这个异常包含了一个标准的HTTP响应代码或者下面异常代码之一。为了获取与异常相联系的错误代码,调用MediaException.getCode().

异常代码

描述

INVALID_HEADER

媒体格式无效。

REQUEST_TIMED_OUT

请求超时。

INTERRUPTED_DOWNLOAD

应用程序调用MediaManager.cancel()来取消下载。

UNSUPPORTED_TYPE

媒体类型(MIME类型)不支持。

UPGRADE_PALYER

媒体引擎的版本和请求的内容不兼容。

UPGRADE_MEDIA

媒体引擎的版本不在支持请求的内容。

CHECKSUM_MISMACTH

求和校验失败,因此媒体内容不能读取。

OUT_OF_BOUNDS

数组出界,或应用程序试图访问一个文件结尾后的输入流。

事件

MediaListener接口允许应用程序接受或响应下面的事件:

事件

描述

MEDIA_REQUEST

媒体已请求加载,当animation自动请求新内容或当用户点击媒体内容的超连接时,事件发生。

MEDIA_REALIZED

媒体已经创建播放了。当MediaManager.createMediaManager()已经调用时发生。

MEDIA_COMPLETE

媒体已经加载,并成功播放。

MEDIA_TO

媒体正在加载。

为获得更多信息,参考85页的“监听Media Engine事件”.

播放媒体内容

为了获取BlackBerry设备或网络上的PME内容,使用MediaManager的方法。为了播放已经下载到BlackBerry设备的PME内容,使用MediaPlayer类的方法。

下载内容

为下载PME内容,创建一个MediaManager对象,然后调用MediaManager.createMedia().

try

{

Object media = manager.createMedia("http://webserver/sample.pme");

}

catch (IOException ioe)

{

System.out.println("Error: requested content was not downloaded.");

}

catch (MediaException me)

{

System.out.println("Error: “ + me.getCode());

}

:下面缺省的协议会被支持:http://,https://.jar://,和cod://.为获得更多信息,参看81页的“媒体加载”。

第一次调用MediaManager.createMedia(),URL必须是绝对路径,除非首先调用MediaManager.setProperty(“URI_BASE”,<base_url>)设置基URL路径。当你之后调用createMedia()时,前面的URL作为基URL。

播放PME内容

为播放设置PME对象

调用MedialPlayer.setMedia().

MediaPlayer player = new MediaPlayer();

try

{

player.setMedia(media);

}

catch (MediaException me)

{

System.out.println("Error: requested content type is not supported.”);

}

 

获取一个显示PME内容的UI对象

调用MediaPlayer.getUI()。转化getUI()返回的一个作为Field的对象,然后将之加入到屏幕来显示。

add((Field)player.getUI());

开始播放下载的PME内容

调用MediaPlayer.start()。

if(player.getState() == MediaPlayer.REALIZED)

{

try

{

player.start();

}

catch(MediaException me) {

System.out.println("Error occurred during media playback: " +

me.getCode() + me.getMessage());

}

}

:在调用MediaPlayer.start()前检查MediaPlayer的状态,如果媒体播放器不是REALIZED状态,start()方法抛出一个异常。

代码实例

MediaSample.java实例从一个Web服务器获取一个PME文件,然后显示它。


例:MediaSample.java

/**

* MediaSample.java

* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.mediasample;

import java.io.*;

import net.rim.device.api.ui.*;

import net.rim.device.api.ui.component.*;

import net.rim.device.api.ui.container.*;

import net.rim.device.api.system.*;

import net.rim.plazmic.mediaengine.*;

public class MediaSample extends UiApplication {

public static void main(String[] args) {

MediaSample app = new MediaSample();

app.enterEventDispatcher();

}

public MediaSample() {

pushScreen(new MediaSampleScreen());

}

final static class MediaSampleScreen extends MainScreen {

public MediaSampleScreen() {

super();

LabelField title = new LabelField(“Media Sample”, LabelField.ELLIPSIS| LabelField.USE_ALL_WIDTH);

setTitle(title);

MediaPlayer player = new MediaPlayer();

MediaManager manager = new MediaManager();

try {

Object media = manager.createMedia(“http://webserver/SVGFILE.pme”);

player.setMedia(media);

}

catch (IOException ioe) {

}

catch (MediaException me) {

System.out.println(“Error during media loading: “);

System.out.println(me.getCode());

System.out.println(me.getMessage());

}

add((Field)player.getUI());

try {

player.start();

}

catch(MediaException me) {

System.out.println(“Error occured during media playback: “);

System.out.println(me.getCode());

System.out.println(me.getMessage());

}

}

}

}


监听媒体引擎事件

MediaListener接口允许应用程序注册接收媒体引擎事件。应用程序可以在注册MediaPlayer和MediaEngine对象上注册监听者。

当应用程序实现监听者时,它可以完成以下的动作:

  • 提供内容下载状态的信息。
  • 在后台下载内容,当完成时播放它。
  • 下载一个animation自动请求的内容。

MediaListener接口包含一个方法,listen方法。

public void mediaEvent(Object sender,

int event,

int eventParam,

Object data);

参数

描述

sender

本参数引用了发送事件的对象,如MediaPlayer或MediaManager对象。

event

参数可以是下列事件之一:

  • MEDIA_REQUESTED:当新的内容请求时发送事件。
  • MEDIA_COMPLETE:当所有计划好的媒体动作完成时触发事件。
  • MEDIA_REALIZED:由MediaManager发送,返回下载的媒体。
  • MEDIA_IO:由MediaPlayer发送,提供现在进度或状态的信息。

eventParam

不要使用这个参数,因为它可能接收一个任意值。它存在是为了为额外的事件提供一个一致的接口。

data

当data参数是MEDIA_REQUESTED,data把请求的URL作为一个String对象。

当data参数是MEDIA_REALIZED,data引用了创建的媒体对象。

当data参数是MEDIA_IO,data引用了一个net.rim.plazmic.mediaengine.io.LoadingStatus对象。

监听媒体引擎事件

MediaListener接口的实现允许你的应用程序监听一个媒体引擎事件。mediaEvent()的实现应该处理所有可能的媒体事件。下面的例子使用了一个switch语句来处理可能媒体事件。

public final class MediaListenerImpl implements MediaListener {

public void mediaEvent(Object sender, int event, int eventParam, Object data) {

switch(event) {

case MEDIA_REQUESTED:

// Perform action.

break;

case MEDIA_COMPLETE:

// Perform action.

break;

case MEDIA_REALIZED:

// Perform action.

break;

case MEDIA_IO:

// Perform action.

break;

}

}

}

注册监听者

为了注册你的监听者,调用MediaPlayer和MediaManager对象上的addMediaListener()方法。

private MediaListenerImpl _listener = new MediaListenerImpl();

private MediaPlayer player = new MediaPlayer();

private MediaManager manager = new MediaManager();

player.addMediaListener(_listener);

manager.addMediaListener(_listener);

在后台加载内容

当实现MediaListener时,你可以在背后下载PME内容,并且当下载完成后播放内容。

调用MediaManager.createMediaListener()为将来的播放下载内容。

:和createMedia()不一样,createMediaLater()不返回一个媒体内容的对象。

在MediaListener.mediaEvent()中,当请求的内容下载时,加入代码来处理MEDIA_REALIZED事件。为了注册在data参数里指定的内容,调用MediaPlayer.setMedia(data)。为了开始播放,调用MediaPlayer.start()。

manager.createMediaLater("http://webserver/sample.pme");

public void mediaEvent(Object sender, int event,

int eventParam, Object data) {

switch(event) {

...

case MEDIA_REALIZED:

try {

player.setMedia(data);

player.start();

}

catch(MediaException me) {

System.out.println("Error playing media” + me.getCode() +" +

"   me.getMessage());

}

break;

}

}

跟踪下载进度

为得到下载进度的信息,使用net.rim.plazmic.mediaengine.io.LoadingStatus类。这个类包含了一些方法来允许你获得媒体内容类型,字节总数,字节读取数,以及内容的源URL。

状态

描述

LOADING_STARTED

加载开始。

LOADING_READING

数据流正在解析。

LOADING_FINISHED

加载媒体成功。

LOADING_FAILED

媒体记载失败.

  • 为获取详细的错误代码,调用getCode().参看82页获得更多详情。
  • 为得到异常信息,调用getMessage().

在mediaEvent()的实现里,当MEDIA_IO事件发生时,将data参数里的Object转化为一个LoadingStatus对象。

调用LoadingStatus.getStatus()来获取下载的状态,然后处理每个状态。

对每个正常的状态,打印一个消息到控制台。

对LOADING_FAILED状态,完成下面的动作:

  • 调用LoadingStatus.getCode()获得错误代码。
  • 调用LoadingStatus.getMessage()获得详细的消息。
  • 调用LoadingStatus.getSource()获得内容的URL字符串。

public void mediaEvent(Object sender, int event,

int eventParam, Object data) {

switch(event) {

...

case MEDIA_IO: {

}

...

break;

}

break;

...

switch(s.getStatus()) {

case LoadingStatus.LOADING_STARTED:

System.out.println("Loading in progress");

break;

case LoadingStatus.LOADING_READING:

System.out.println("Parsing in progress");

break;

case LoadingStatus.LOADING_FINISHED:

System.out.println("Loading completed");

break;

case LoadingStatus.LOADING_FAILED:

String errorName = null;

int code = s.getCode();

switch (code) {

case MediaException.INVALID_HEADER:

errorName = "Invalid header" + "\n" + s.getSource();

break;

case MediaException.REQUEST_TIMED_OUT:

errorName = "Request timed out" + "\n" +

s.getSource();

break;

case MediaException.INTERRUPTED_DOWNLOAD:

break;

case MediaException.UNSUPPORTED_TYPE:

errorName = "Unsupported type" + s.getMessage() + "\n" + s.getSource();

break;

default: {

if (code > 200) {

// A code > 200 indicates an HTTP error

errorName = "URL not found";

}

else {

// default unidentified error

errorName = "Loading Failed";

}

errorName += "\n" + s.getSource() + "\n" + s.getCode()+ ": " + s.getMessage();

break;

}

}

System.out.println(errorName);

break;

} // End switch s.getStatus().

break;

}

代码实例

MediaSample2.java 实例实现了一个监听者在后台下载媒体内容,并显示下载的状态到控制台。


例:MediaSample2.java

/**

* MediaSample2.java

* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.mediasample;

import java.io.*;

import net.rim.device.api.ui.*;

import net.rim.device.api.ui.component.*;

import net.rim.device.api.ui.container.*;

import net.rim.device.api.system.*;

import net.rim.plazmic.mediaengine.*;

import net.rim.plazmic.mediaengine.io.*;

public class MediaSample2 extends UiApplication {

private MediaPlayer player = new MediaPlayer();

private MediaManager manager = new MediaManager();

private MediaListenerImpl _listener = new MediaListenerImpl();

private MediaSample2Screen _screen;

public static void main(String[] args) {

MediaSample2 app = new MediaSample2();

app.enterEventDispatcher();

}

public MediaSample2() {

_screen = new MediaSample2Screen();

pushScreen(_screen);

}

public final class MediaListenerImpl implements MediaListener {

public void mediaEvent(Object sender, int event,

int eventParam, Object data) {

switch(event) {

case MEDIA_REQUESTED:

System.out.println(“Media requested”);

break;

case MEDIA_COMPLETE:

System.out.println(“Media completed”);

break;

case MEDIA_REALIZED:

try {

player.setMedia(data);

player.start();

}

catch(MediaException me) {

System.out.println(“Error during media loading: “ +

me.getCode() + me.getMessage());

}

break;

case MEDIA_IO: {

LoadingStatus s = (LoadingStatus)data;

switch(s.getStatus()) {

case LoadingStatus.LOADING_STARTED:

System.out.println(“Loading in progress”);

break;

case LoadingStatus.LOADING_READING:

System.out.println(“Parsing in progress”);

break;

case LoadingStatus.LOADING_FINISHED:

System.out.println(“Loading completed”);

break;

case LoadingStatus.LOADING_FAILED:

String errorName = null;

int code = s.getCode();

switch (code) {

case MediaException.INVALID_HEADER:

errorName = “Invalid header” + “\n” + s.getSource();

break;

case MediaException.REQUEST_TIMED_OUT:

errorName = “Request timed out” + “\n” + s.getSource();

break;

case MediaException.INTERRUPTED_DOWNLOAD:

break;

case MediaException.UNSUPPORTED_TYPE:

errorName = “Unsupported type” + s.getMessage()

+ “\n” + s.getSource();

break;

default: {

if (code > 200) {

// A code > 200 indicates an HTTP error.

errorName = “URL not found”;

}

else {

// Default unidentified error.

errorName = “Loading Failed”;

}

errorName += “\n” + s.getSource() + “\n”+

s.getCode() + “: “ + s.getMessage();

break;

}

}

System.out.println(errorName);

break;

} // End switch s.getStatus().

break;

}

}

}

}

final class MediaSample2Screen extends MainScreen {

public MediaSample2Screen() {

super();

LabelField title = new LabelField(“Media Sample”, LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);

setTitle(title);

manager.addMediaListener(_listener);

// Change this to the location of a test .pme file.

manager.createMediaLater(“http://test.rim.com/SVGBS0001.pme”);

add((Field)player.getUI());

}

}

}


创建一个定制的连接

MediaManager使用一个Connector对象加载媒体,并打开输入流。缺省的Connector支持下列协议:http://.https://,jar://,以及cod://。为了增加支持一个定制的协议或者为了覆写缺省的行为,通过实现net.rim.plazmic.mediaengine.io.Connector接口创建一个定制的Connector

方法签名

实现

InputStream getInputStream(String, ConnectionInfo)

实现本方法返回一个输入流从指定URI读取内容。

void releaseConnection(ConnectionInfo)

实现本方法释放连接。MediaManager调用本方法来通知Connector可以释放连接了。

void setProperty(String, String)

实现本方法设置连接指定的属性。

实现一个定制的connector

为了完成处理一个定制的协议,实现Connector接口,包含getInputStream()。为了处理一个标准的协议,调用缺省的Connector。

setProperty(String name, String value)的实现设置了指定的属性。在本例中,connector不必设置任何指定的属性,因此setProperty()的实现调用了Connector上的setProperty()。

public class SampleConnector implements Connector {

Connector delegate; // The default Connector.

SampleConnector(Connector delegate) {

this.delegate = delegate;

}

public InputStream getInputStream(String uri, ConnectionInfo info)

throws IOException, MediaException {

InputStream input = null;

if (uri.startsWith("myprotocol://")) {

// Perform special tasks.

info.setConnection(new MyProtocolConnection());

info.setContentType("application/x-vnd.rim.pme");

// openMyInputStream() is a custom method that opens

//stream for "myprotocol://".

input = openMyInputStream(uri);

}

else {

input = delegate.getInputStream(uri, info);

}

return input;

}

public void releaseConnection(ConnectionInfo info)

throws IOException, MediaException {

Object o = info.getConnection();

if (o instanceof MyProtocolConnection) {

((MyProtocolConnection)o).close(); // Perform cleanup.

}

else

{

delegate.releaseConnection(info);

}

}

public void setProperty(String property, String value) {

delegate.setProperty(property, value);

}

}

注册一个定制的连接器

在你的主要方法里,调用MediaManager.setConnector()注册你的定制的连接器。

MediaManager manager = new MediaManager();

manager.setConnector(new CustomPMEConnector(manager.getDefaultConnector()));

代码实例

CustomPMEConnector.java实例为实现一个定制的连接器提供了一个框架。


例:CustomPMEConnector.java

/*

* CustomPMEConnector.java

* Copyright (C) 2003-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.mediasample;

import java.io.*;

import net.rim.plazmic.mediaengine.*;

import net.rim.plazmic.mediaengine.io.*;

public class CustomPMEConnector implements Connector {

private Connector delegate;

private InputStream input;

CustomPMEConnector(Connector delegate)

{

this.delegate = delegate;

}

public InputStream getInputStream(String uri, ConnectionInfo info)

throws IOException, MediaException

{

if (uri.startsWith("myprotocol://"))

{

// Perform special tasks.

info.setConnection(new MyProtocolConnection());

info.setContentType("application/x-vnd.rim.pme");

// OpenMyInputStream() is a custom method that opens

//stream for “myprotocol://”

input = openMyInputStream(uri);

}

else

{

input = delegate.getInputStream(uri, info);

return input;

}

private InputStream openMyInputStream(String uri)

{

InputStream input = null;

}

// @todo: open stream here

return input;

}

public void releaseConnection(ConnectionInfo info)

throws IOException, MediaException

{

Object o = info.getConnection();

if (o instanceof MyProtocolConnection)

{

((MyProtocolConnection)o).close(); // Perform cleanup.

}

else

{

delegate.releaseConnection(info);

}

}

public void setProperty(String property, String value) {

delegate.setProperty(property, value);

}

// Inner class that defines the connection class.

public static class MyProtocolConnection {

public MyProtocolConnection()

{

// ...

}

public void close()

{

// ...

}

}

}

  • Last Updated:2008年4月18日
  • Last Updated:2007年1月10日
  • Last Updated:2006年4月28日

转载于:https://www.cnblogs.com/confach/articles/387902.html

BlackBerry 应用程序开发者指南 第一卷:基础--第5章 支持的媒体内容(Media Content)...相关推荐

  1. BlackBerry 应用程序开发者指南 第一卷:基础--第9章 IT策略(Policy)

    作者:Confach 发表于2006-04-28 21:44 版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息. http://www.cnblogs.com/confa ...

  2. BlackBerry 应用程序开发者指南 第一卷:基础--第7章 使用数据报(Datagram)连接...

    作者:Confach 发表于2006-04-28 21:42 pm 版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息. http://www.cnblogs.com/co ...

  3. BlackBerry 应用程序开发者指南 第一卷:基础--第8章 本地化应用程序

    作者:Confach 发表于2006-04-28 21:43 pm 版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息. http://www.cnblogs.com/co ...

  4. BlackBerry 应用程序开发者指南 第二卷:高级--第11章 管理通知(Notification)

    作者:Confach 发表于 2006-04-29 20:28 pm 版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息. http://www.cnblogs.com/c ...

  5. BlackBerry 应用程序开发者指南 第二卷:高级--第7章 与BlackBerry应用程序通信

    作者:Confach 发表于2006-04-28 22:22 pm 版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息. http://www.cnblogs.com/co ...

  6. BlackBerry 应用程序开发者指南 第二卷:高级--第13章 应用程序间共享运行时对象...

    作者:Confach 发表于 2006-04-29 20:30 pm 版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息. http://www.cnblogs.com/c ...

  7. BlackBerry 应用程序开发者指南 第二卷:高级--第4章 增加设备选项

    作者:Confach 发表于2006-04-28 22:18 pm 版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息. http://www.cnblogs.com/co ...

  8. 顶级c程序员之路 基础篇 - 第一章 关键字的深度理解 number-1

    c语言有32个关键字,每个关键字你都理解吗? 今天出场的是: auto ,  register,  static,   extern 为什么他们会一起呢,说到这里不得不谈到c语言对变量的描述. c给每 ...

  9. 百度智能小程序搜索优化指南(基础版)

    目录  一.为什么百度搜索喜欢智能小程序 二.开发前必读内容 2.1 必须了解的搜索知识 2.2 掌握常用工具 2.3 如何搭建智能小程序更友好 三.智能小程序资源如何进入搜索 3.1 接入自然搜索结 ...

最新文章

  1. 【洛谷】P1388 算式(dp)
  2. final,finally,finaliz的区别(Java)
  3. bzoj4013: [HNOI2015]实验比较
  4. ffplay.c学习-5-视频输出和尺⼨变换
  5. Angular应用里的tsconfig.app.json
  6. WebService客户端开发(Axis2 1.5)
  7. 三星笔记本进入BIOS后找不到U盘启动项/快速启动键F12没有反应
  8. java transient简单介绍
  9. 别再双塔了!谷歌提出DSI索引,检索效果吊打双塔,零样本超BM25!
  10. 关于PyTorch中的register_forward_hook()函数未能执行其中hook函数的问题
  11. IOT(3)---传感器厂家
  12. Flink : UnknownTaskExecutorException: No TaskExecutor registered under
  13. mysql一次运行多个SQL文件
  14. AutoResetEvent 与 ManualResetEvent
  15. 面对SDN,我们该怎么办?
  16. 安信可Ca-01 4G模块调试
  17. python3爬虫抓取链家上海租房信息
  18. 语义网络,语义网,链接数据和知识图谱
  19. Eric Berg:帮助你了解及根治痘痘痤疮的观点
  20. 电子发票电子化报销入账归档 给区块链领域带来了什么样的机遇

热门文章

  1. manjaro linux下载软件,manjaro linux
  2. java读取gxk文件,Java中常见的IO流及其使用
  3. 传输层:IP 地址解析 路由转发
  4. 1040 有几个PAT (25 分
  5. libevent项目分析(一) -- 准备阶段
  6. Java进阶面试资料无偿分享!真香系列
  7. java拦截器和过滤器,2021最新版!
  8. 我们究竟还要学习哪些Android知识?满满干货指导
  9. 灵魂拷问!一起刷完了这份1307页的安卓面试宝典吧,不吃透都对不起自己
  10. python学习:re模块