进行数据解析的理由不计其数,相关的工具和技巧也同样如此。但是,当您需要用这些数据做一些新的事情时,即使有“合适的”工具可能也是不够的。这一担心对于异类数据源的集成同样存在。用来做这项工作的合适工具迟早应该是一种编程语言。

Oracle 提供了一些非常强大的实用程序来加载、处理和卸载数据。SQL*Loader、Data Pump、外部表、Oracle Text、正则表达式都能提供这些功能。然而人们常常会需要在数据库外做一些事情(或者,说得琐碎些,可能您还没有获得必要的数据库权限)。

利用 Python 可以进行高水平的、有效的数据解析。而利用互联网上免费提供的大量标准库和众多模块可以处理数据逻辑,不必手动剖析字节。

字符串理论

文本解析的最低级别是字符串。Python 并不把字符区分为单独的数据类型,但却区分普通字符串和 Unicode 字符串类型。字符串可以括在单引号、双引号或三引号中,并且是 Python 的一种不可变对象 — 一旦创建就不能对其进行修改。每一个操作都会创建一个新的字符串对象。对于具有静态类型语言经验的编程人员而言,乍听上去这可能真得很奇怪,但此类实现有一些特定的原因,多数与性能有关。

因为 Python 完全支持 Unicode,所以处理多语言信息不存在问题。手动创建 Unicode 字符串时,您可以选择直接在字符串前使用 u 前缀(如 u"Unicode text")或者使用内置的 unicode() 函数。可以使用 unicode() 或 encode() 方法在任何支持的字符集中对字符串进行编码。有关支持的编码列表,请查阅 Python 库参考 的标准编码部分或使用导入编码;输出 encodings._aliases.keys()。

您可以放心地使用 UTF-8 编写 Python 程序,记住仅变量名必须是有效的 ASCII 字符串。注释可以是希腊文、汉字或任意内容。不过,这样的文件或者要求使用附加字节顺序标记 (BOM) 的编辑器来保存,或者,需要您编写第一行代码:

# -*- coding: utf-8 -*-

字符串提供有一组方法可用于进行大多数有用的文本操作,如 find()、split()、rjust() 或 upper()。它们在内置的 str 类型上实现,该类型可以表示普通字符串和原始字符串。(原始字符串与普通字符串对反斜线的解释不同。)

>>>  zen = "Explicit is better than implicit."
>>> print zen.title()
'Explicit Is Better Than Implicit.'
>>> zen.split(' ')
['Explicit', 'is', 'better', 'than', 'implicit.']
>>> zen.rstrip('.').lower().replace('is', 'is always')
'explicit is always better than implicit'

Python 的可迭代类型的最棒的一个特性是索引方法。普通索引以 0 开始而负索引向后计数,所以 [-1] 表示最后一个字符,[:5] 表示前 5 个字符,而 [5:-5] 表示前 5 个和后 5 个字符组成的字符串。

>>>  sample = "Oracle Database"
>>> sample[0]
'O'
>>> sample[0:6], sample[7:15]
('Oracle', 'Database')
>>> sample[-8:]
'Database'
>>> sample[sample.index('Data')+4:]
'base'

正则表达式

Python 当然支持正则表达式。事实上,Python 的正则表达式 re 模块支持 Unicode、匹配、搜索、拆分、替换和分组。如果您熟悉 Oracle 对正则表达式的实现方式,您就不会对 Python 的函数感到陌生。

在详细比较 Python 和 Oracle 对正则表达式的实现时,值得注意的差异包括:

  • 当关系设计要求一种不同于编程语言 1 的方法时,re.search() 可用于代替 Oracle 的 REGEXP_LIKE、REGEXP_INSTR 和 REGEXP_SUBSTR。

  • 对 Python 语法改写后,re.sub() 的使用方式可以与 REGEXP_REPLACE 完全相同。不过,要注意 Oracle 的位置参数从 1 开始,而 Python 编制任何索引时都从 0 开始。

  • Oracle 的 match_parameter 表示正则表达式的一组标志,方式与 Python 在搜索模式或模式对象编译属性中使用 (?iLmsux) 语法的方式相同。要获得有效标志的列表,请比较 Python 库参考 的 4.2.3 节和 Oracle 数据库 SQL 语言参考 中 match_parameter 的有效值列表。

Python 的 re.search() 函数非常灵活,这归功于正则表达式这一基本概念。re 模块的最底层有一个对象,它表示匹配模式的方式允许以多种不同的方法对源字符串进行剖析。re.compile() 函数返回一个采用某一模式和若干可选标志的编译模式对象,如 re.I,它表示不区分大小写的匹配。

>>>  import re
>>> p = re.compile("^a.*", re.I)
>>> print p
<_sre.SRE_Pattern object at 0x011CA660>

您无须显式编译正则表达式。re 模块中的函数以透明方式完成此工作。如果代码中多处用到编译模式,使用该模式非常有益,但是如果该模式仅使用一次,则不需要这样的编码开销。

Python 中有六个正则表达式编译标志:

  • I (IGNORECASE) 用于不区分大小写的匹配

  • L (LOCALE) 使得特殊的序列(如词和空格)与语言设置相关

  • M (MULTILINE) 意味着在多行中搜索该模式,这样 ˆ 可以匹配字符串的开始位置和每一个换行符后面的位置,$ 可以匹配每一个换行符前面的位置和字符串的结束位置

  • S (DOTALL) 强制使用点专用字符 (.) 匹配任意字符,包括换行符

  • U (UNICODE) 使得特殊的序列可以识别 Unicode

  • X (VERBOSE) 可以增强您编写的正则表达式的可读性。

要一次使用多个标志,只需将它们加在一起即可 — 如 re.compile("Oracle", re.I+re.S+re.M)。另一种方式是使用 (?iLmsux) 语法将使用所需数量的标志选项作为搜索模式的前缀。这样,前一表达式可写作 re.compile("(?ism)Oracle")。

有关使用正则表达式的最好建议是尽可能地避免使用它们。在将它们嵌入代码前,请确定没有字符串方法可以完成相同的工作,因为字符串方法更快且不会带来导入以及正则表达式处理这些额外的开销。在字符串对象上使用 dir() 就可以看到可用的内容。

下例展示了在 Python 这样一种动态语言中看待正则表达式的方式。解析 tnsnames.ora 文件以便为每个网络别名创建简单连接字符串(将 file() 函数指向您的 tnsnames.ora 文件的位置):

>>> import re
>>> tnsnames = file(r'tnsnames.ora').read()
>>> easy_connects = {}
>>> tns_re = "^(\w+?)\s?=.*?HOST\s?=\s?(.+?)\).*?PORT\s?=\s?(\d+?)\).

*?SERVICE_NAME\s?=\s?(.+?)\)"
>>> for match in re.finditer(tns_re, tnsnames, re.M+re.S):
...  t = match.groups()
...  easy_connects[t[0]] = "%s:%s/%s" % t[1:]
>>> print easy_connects

此程序在 Oracle Database XE 默认的 tnsnames.ora 文件上的输出是:

{'XE': 'localhost:1521/XE'}

请注意,此正则表达式非常愚钝,会被 IPC 条目所阻塞,因此需要将这些条目放在文件的结尾处。解析匹配圆括号是一个 NP 完成问题。

因为提供有多种公开方法,Python 匹配对象的功能非常强大,这些方法包括 span()(它可以返回匹配范围)、group()(它可以按给定的索引返回匹配组)以及 groupdict()(它可以在模式含有命名的组时以字典形式返回匹配组)。

逗号分隔值

CSV 格式因其简洁性和跨平台设计常用于组织间的信息交换。使用正则表达式通常可以轻松地解析逗号分隔值,但使用 Python 的 csv 模块可以使此任务变得更为容易。

使用该模块要求开发人员熟悉该模块所采用的逻辑。有关 CSV 文件的最重要的信息是它的“方言”,它包含分隔符、引号字符、行终止符等相关信息。Python 2.5 中目前可用的方言是 excel 和 excel-tab。内置的嗅探器总是试图猜测正确的格式。写入器与阅读器对象支持 CSV 数据的输入和输出。

就本例而言,我用的是 HR 模式的 JOBS_HISTORY 表中的数据。它演示了如何直接从一个 SQL 查询创建 CSV 文件 job_history.csv。

>>> import csv
>>> import cx_Oracle
>>> db = cx_Oracle.connect('hr/hrpwd@localhost:1521/XE')
>>> cursor = db.cursor()
>>> f = open("job_history.csv", "w")
>>> writer = csv.writer(f, lineterminator="\n", quoting=csv.QUOTE_NONNUMERIC)
>>> r = cursor.execute(" "SELECT * FROM job_history ORDER BY employee_id, start_date")
>>> for row in cursor:
...   writer.writerow(row)
...
>>> f.close()

该文件包含:

101,"1989-09-21 00:00:00","1993-10-27 00:00:00","AC_ACCOUNT",110
101,"1993-10-28 00:00:00","1997-03-15 00:00:00","AC_MGR",110
102,"1993-01-13 00:00:00","1998-07-24 00:00:00","IT_PROG",60
114,"1998-03-24 00:00:00","1999-12-31 00:00:00","ST_CLERK",50
122,"1999-01-01 00:00:00","1999-12-31 00:00:00","ST_CLERK",50
176,"1998-03-24 00:00:00","1998-12-31 00:00:00","SA_REP",80
176,"1999-01-01 00:00:00","1999-12-31 00:00:00","SA_MAN",80
200,"1987-09-17 00:00:00","1993-06-17 00:00:00","AD_ASST",90
200,"1994-07-01 00:00:00","1998-12-31 00:00:00","AC_ACCOUNT",90
201,"1996-02-17 00:00:00","1999-12-19 00:00:00","MK_REP",20

或者,您也可以使用 Oracle SQL Developer 以 CSV 格式导出数据。

可以通过以下方式读取该 CSV 文件:

>>>  reader = csv.reader(open("job_history.csv", "r"))
>>>  for employee_id, start_date, end_date, job_id, department_id in reader:
...   print job_id,
...
JOB_ID IT_PROG AC_ACCOUNT AC_MGR MK_REP ST_CLERK ST_CLERK

AD_ASST SA_REP SA_MAN AC_ACCOUNT

注意我不必在上面显式指定方言,它是自动推断出的。我只是输出了 job_id 列,但对这样经过解析的文件我确实可以做的是将其插入数据库中。为确保日期得到正确处理,在批量插入前对 NLS_DATE_FORMAT 进行手动设置。

SQL> CREATE TABLE job_his (
2 employee_id NUMBER(6) NOT NULL,
3 start_date DATE NOT NULL,
4 end_date DATE NOT NULL,
5 job_id VARCHAR2(10) NOT NULL,
6 department_id NUMBER(4)
7 ); >>> reader = csv.reader(open("job_history.csv", "r"))
>>> lines = []
>>> for line in reader:
... lines.append(line)
...
>>> cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'")
>>> cursor.executemany("INSERT INTO job_his VALUES(:1,:2,:3,:4,:5)", lines)
>>> db.commit()

如果您使用 SQL Developer 创建该 CSV 文件,则可能需要修改日期格式,如下所示:

>>> cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YY/MM/DD'")

csv 模块美中不足的地方是缺乏原生 Unicode 支持。有关解决方案和使用 CSV 文件的更多示例,请参见 Python 库参考 的 9.1.5 示例部分

URL

urlparse 模块使您可以将统一资源定位器字符串分解为各个组成部分,分别表示 URL 模式、网络位置、路径、参数、查询字符串、碎片标识符、用户名、口令、主机名和/或端口。Python 2.5 支持 24 个最常用的模式,包括 svn+ssh、sftp 和 mms。下例显示了 urlparse 模块的一些特性:

>>>  from urlparse import urlparse
>>> url = "http://www.oracle.com/technology/index.html?rssid=rss_otn_news#section5"
>>> pr = urlparse(url)
>>> print type(pr)
<class 'urlparse.ParseResult'>
>>> print pr.hostname
www.oracle.com
>>> print pr.query
rssid=rss_otn_news
>>> print url==pr.geturl()
True

RSS 信源

RSS 基于一个非常简单的概念:您在事件发生时获得它的最新消息,而不是碰巧发现。整合许多不同来源的 RSS 信源是开发领域的一个流行趋势,对新闻信源聚合器和 Web 2.0 混搭尤其如此。

RSS 是 XML 的一种方言,因此使用 Python 提供的一种 XML 解析器可轻松地对其进行处理。Python 标准库本身还没有提供用于解析信源的模块。不过,feedparser.org 免费提供一个稳定的、经过广泛检验的通用信源解析器。由于它没有外部依赖性,因此这是快速熟悉模块安装概念的一个很好的机会。

下载 feedparser 模块的最新版本(撰写此文时为 4.1)后,对其进行解压缩并将工作目录修改为 feedparser-4.1。在控制台/命令提示符下,运行 python setup.py install。此命令将模块放入 Python 文件夹,使其立即可供使用。就是这样。

了解一下 Oracle 的动态如何?

>>> import feedparser
>>> import time
>>> rss_oracle = feedparser.parse("http://www.oracle.com/technology/syndication/rss_otn_news.xml")
>>> for e in rss_oracle.entries[:5]:
..    t = time.strftime("%Y/%m/%d", e.updated_parsed)
..    print t, e.title
        
2007/07/23 Integrating Oracle Spatial with Google Earth
2007/07/11 Oracle Database 11g Technical Product Information Now Available
2007/07/11 Explore the Oracle Secure Enterprise Search Training Center
2007/07/09 Implementing Row-Level Security in Java Applications
2007/06/29 Build Your Own Oracle RAC Cluster on Oracle Enterprise Linux and iSCSI

feedparser 模块具有足够的智能,可以正确解析日期、处理 HTML 标记、规范内容以便可以针对所有支持的 RSS 和 ATOM 变体使用一致的 API、解析相对链接、检测有效字符编码等。

接下来解析什么?

有了正则表达式工具箱,您可以搜索几乎所有的纯文本内容。至于解析文本数据,Python 有很多其他特性,包括:

  • email.parse,用于解析电子邮件消息
  • ConfigParser,用于解析从 Windows 系统中获得的 INI 配置文件
  • robotparser 模块,用于解析您 Web 站点的 robots.txt
  • optparse 模块,用于进行强大的命令行参数解析
  • HTMLParse 模块中的 HTMLParse 类,用于有效地解析 HTML 和 XHTML(类似于 SAX)
  • 若干 XML 解析器(xml.dom、xml.sax、xml.parsers.expat、xml.etree.ElementTree)

对于二进制数据,您可以利用 binascii 模块,它包含一组函数可用于在二进制编码数据和 ASCII 编码数据之间转换,并附带了分别用于 base64 和 uuencode 转换的 base64 和 uu 模块。

总结

这篇方法文档介绍了在 Python 中进行数据解析所采用的一些基本和高级的技巧。您现在应当已经认识到了 Python 附带的标准库的威力。在开始制作您自己的解析器之前,首先检查一下所需的功能是否已可供导入。

字符串操作比正则表达式操作速度快,同时足以满足很多的编程需要。但是到底选用 Python 还是 Oracle 正则表达式函数取决于您的应用程序逻辑和业务需要。

精通 Oracle+Python,第 3 部分:数据解析的更多相关文章

  1. python爬虫的页面数据解析和提取/xpath/bs4/jsonpath/正则(1)

    一.数据类型及解析方式 一般来讲对我们而言,需要抓取的是某个网站或者某个应用的内容,提取有用的价值.内容一般分为两部分,非结构化的数据 和 结构化的数据. 非结构化数据:先有数据,再有结构, 结构化数 ...

  2. python爬虫---爬虫的数据解析的流程和解析数据的几种方式

    python爬虫---爬虫的数据解析的流程和解析数据的几种方式 一丶爬虫数据解析 概念:将一整张页面中的局部数据进行提取/解析 作用:用来实现聚焦爬虫的吧 实现方式: 正则 (针对字符串) bs4 x ...

  3. 精通 Oracle+Python,第 9 部分:Jython 和 IronPython — 在 Python 中使用 JDBC 和 ODP.NET

    成功的编程语言总是会成为顶级开发平台.对于 Python 和世界上的两个顶级编程环境 Java 和 Microsoft .NET 来说的确如此. 虽然人们因为 Python 能够快速组装不同的软件组件 ...

  4. 精通 Oracle+Python,第 2 部分:处理时间和日期

    从 Python 2.4 版开始,cx_Oracle 自身可以处理 DATE 和 TIMESTAMP 数据类型,将这些列的值映射到 Python 的 datetime 模块的 datetime 对象中 ...

  5. Python爬虫之三种数据解析方式

    一.引入 二.回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需 ...

  6. 05 Python网络爬虫的数据解析方式

    一.爬虫数据解析的流程 1.指定url 2.基于requests模块发起请求 3.获取响应中的数据 4.数据解析 5.进行持久化存储 二.解析方法 (1)正则解析 (2)bs4解析 (3)xpath解 ...

  7. 精通 Oracle+Python,第 1 部分:查询最佳应践

    原文链接:http://www.oracle.com/technetwork/cn/articles/dsl/mastering-oracle-python-1391323-zhs.html 在 Py ...

  8. 精通 Oracle+Python,第 8 部分:适合 Oracle DBA 使用的 Python

    传统上,当需要为操作系统编写一些脚本时,人们常常会选用 Bash 或 Perl 脚本工具.这些工具易于使用,因而它们几乎变得无处不在,渗透到了包括 Oracle Database 在内的其他软件中,O ...

  9. 精通 Oracle+Python,第 6 部分:Python 支持 XML

    无可辩驳的是,XML 现在是软件中信息交换的实际标准. 因此,Oracle 数据库附带了各种与 XML 相关的增强和工具,它们统称为 Oracle XML DB.XML DB 包含一系列嵌入到数据库中 ...

随机推荐

  1. Node调试工具JSHint

    Node调试工具JSHint的安装及配置教程 作者: 字体:[增加 减小] 类型:转载 时间:2014-05-27我要评论 Node的优势我就不再乱吹捧了,它让javascript统一web的前后台成 ...

  2. bootstrap学习笔记--bootstrap网格系统

    移动设备优先 移动设备优先是 Bootstrap 3 的最显著的变化. 在之前的 Bootstrap 版本中(直到 2.x),您需要手动引用另一个 CSS,才能让整个项目友好的支持移动设备. 现在不一 ...

  3. Java为何大行其道

    Java为何大行其道 --专訪传智播客冯威老师 冯威老师,多年来一直从事软件开发和教学工作.先后担任过项目经理.软件架构师.软件开发project师.系统架构师.讲师等.具备丰富的软件开发经验和教学经 ...

  4. [AngularJS] Extract predicate methods into filters for ng-if and ng-show

    Leaking logic in controllers is not an option, filters are a way to refactor your code and are compa ...

  5. hdu 4651 Partition (利用五边形定理求解切割数)

    下面内容摘自维基百科: 五边形数定理[编辑] 五边形数定理是一个由欧拉发现的数学定理,描写叙述欧拉函数展开式的特性[1] [2].欧拉函数的展开式例如以下: 亦即 欧拉函数展开后,有些次方项被消去,仅 ...

  6. pip安装 MySQLDb 和 Django

    wget "https://pypi.python.org/packages/source/p/pip/pip-1.5.4.tar.gz#md5=834b2904f92d46aaa33326 ...

  7. ClassLoader(摘录)

    Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需要完成以下 ...

  8. oracle修改登录认证方式

    通过配置sqlnet.ora文件,我们可以修改oracle登录认证方式. SQLNET.AUTHENTICATION_SERVICES=(NTS);基于操作系统的认证 SQLNET.AUTHENTIC ...

  9. MFC/VC++ 响应回车键的实现

    在VC++中,要实现对回车键的响应实现,一般通过截获消息来响应,即通过处理BOOL PreTranslateMessage(MSG* pMsg)这个函数来处理 实现如下: BOOL PreTransl ...

  10. JS获取图片上传地址

    function getObjectURL(file) { var url = null ; if (window.createObjectURL!=undefined) { // basic url ...