`
youyun_2008
  • 浏览: 110187 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

转 可爱的 Python:Python中的文本处理

阅读更多


    与其它几种流行的脚本语言一样,Python 是一种用于浏览和处理文本数据的优秀工具。本文为 Python 的初学者概述了 Python 的文本处理工具。文章说明了规则表达式的一些常规概念,并提供了处理文本时,什么情况下应使用(或不使用)规则表达式的建议。

什么是 Python?

Python 是由 Guido van Rossum 开发的、可免费获得的、非常高级的解释型语言。其语法简单易懂,而其面向对象的语义功能强大(但又灵活)。Python 可以广泛使用并具有高度的可移植性。




回页首


字符串 -- 不可改变的序列

如同大多数高级编程语言一样,变长字符串是 Python 中的基本类型。Python 在“后台”分配内存以保存字符串(或其它值),程序员不必为此操心。Python 还有一些其它高级语言没有的字符串处理功能。

在 Python 中,字符串是“不可改变的序列”。尽管不能“按位置”修改字符串(如字节组),但程序可以引用字符串的元素或子序列,就象使用任何序列一样。Python 使用灵活的“分片”操作来引用子序列,字符片段的格式类似于电子表格中一定范围的行或列。以下交互式会话说明了字符串和字符片段的的用法:

字符串和分片

>>> s =
        "mary had a little lamb"
>>> s[0]
        # index is zero-based

        'm'
>>> s[3] =
        'x'
        # changing element in-place fails
Traceback (innermost last):
File
        "<stdin>", line 1,
       
          in
         ?
TypeError: object doesn't support item assignment
>>> s[11:18]
        # 'slice' a subsequence

        'little '
>>> s[:4]
        # empty slice-begin assumes zero

        'mary'
>>> s[4]
        # index 4 is not included in slice [:4]

        ' '
>>> s[5:-5]
        # can use "from end" index with negatives

        'had a little'
>>> s[:5]+s[5:]
        # slice-begin & slice-end are complimentary

        'mary had a little lamb'
     


另一个功能强大的字符串操作就是简单的 in 关键字。它提供了两个直观有效的构造:

in 关键字

>>> s =
        "mary had a little lamb"
>>>
       
          for
         c
       
          in
         s[11:18]:
       
          print
         c,
        # print each char in slice
...
l i t t l e
>>>
       
          if
        
        'x'
       
          in
         s:
       
          print
        
        'got x'
        # test for char occurrence
...
>>>
       
          if
        
        'y'
       
          in
         s:
       
          print
        
        'got y'
        # test for char occurrence
...
got y
     


在 Python 中,有几种方法可以构成字符串文字。可以使用单引号或双引号,只要左引号和右引号匹配,常用的还有其它引号的变化形式。如果字符串包含换行符或嵌入引号,三重引号可以很方便地定义这样的字符串,如下例所示:

三重引号的使用

>>> s2 =
        """Mary had a little lamb
... its fleece was white as snow
... and everywhere that Mary went
... the lamb was sure to go"""
>>>
       
          print
         s2
Mary had a little lamb
its fleece was white as snow
       
          and
         everywhere that Mary went
the lamb was sure to go
     


使用单引号或三重引号的字符串前面可以加一个字母 "r" 以表示 Python 不应该解释规则表达式特殊字符。例如:

使用 "r-strings"

>>> s3 =
        "this \n and \n that"
>>>
       
          print
         s3
this
       
          and

        that
>>> s4 = r
        "this \n and \n that"
>>>
       
          print
         s4
this \n
       
          and
         \n that
     


在 "r-strings" 中,可能另外组成换码符的反斜杠被当作是常规反斜杠。在以后的规则表达式讨论中会进一步说明这个话题。




回页首


文件和字符串变量

我们谈到“文本处理”时,我们通常是指处理的内容。Python 将文本文件的内容读入可以操作的字符串变量非常容易。文件对象提供了三个“读”方法: .read()、.readline() 和 .readlines()。每种方法可以接受一个变量以限制每次读取的数据量,但它们通常不使用变量。 .read() 每次读取整个文件,它通常用于将文件内容放到一个字符串变量中。然而 .read() 生成文件内容最直接的字符串表示,但对于连续的面向行的处理,它却是不必要的,并且如果文件大于可用内存,则不可能实现这种处理。

.readline() 和 .readlines() 非常相似。它们都在类似于以下的结构中使用:

Python .readlines() 示例

        fh = open(
        'c:\\autoexec.bat')
       
          for
         line
       
          in
         fh.readlines():

       
          print
         line

     


.readline() 和 .readlines() 之间的差异是后者一次读取整个文件,象 .read() 一样。.readlines() 自动将文件内容分析成一个行的列表,该列表可以由 Python 的 for ... in ... 结构进行处理。另一方面,.readline() 每次只读取一行,通常比 .readlines() 慢得多。仅当没有足够内存可以一次读取整个文件时,才应该使用 .readline()。

如果正在使用处理文件的标准模块,可以使用 cStringIO 模块将字符串转换成“虚拟文件”(如果需要生成模块的子类,可以使用 StringIO 模块,初学者未必要这样做)。例如:

cStringIO 模块

>>>
       
          import
         cStringIO
>>> fh = cStringIO.StringIO()
>>> fh.write(
        "mary had a little lamb")
>>> fh.getvalue()
        'mary had a little lamb'
>>> fh.seek(5)
>>> fh.write(
        'ATE')
>>> fh.getvalue()
        'mary ATE a little lamb'
     


但是,请记住,cStringIO“虚拟文件”不是永久的,这一点与真正的文件不同。如果不保存它(如将它写入一个真正的文件,或者使用 shelve 模块或数据库),则程序结束时,它将消失。




回页首


标准模块:string

string 模块也许是 Python 1.5.* 标准发行版中最常用的模块。实际上,在 Python 1.6 或更高版本中,string 模块中的功能将作为内置字符串方法(在撰写本文时,详细信息尚未发布)。当然,任何执行文本处理任务的程序也许应该用以下这行开头:

开始使用 string 的方法

      import string


一般经验法则告诉我们,如果 可以 使用 string 模块完成任务,那么那就是 正确 的方法。与 re(规则表达式)相比,string 函数通常更快速,大多数情况下他们更易于理解和维护。第三方 Python 模块,包括某些用 C 编写的快速模块,适用于专门的任务,但可移植性和熟悉性都建议只要可能就使用 string。如果您习惯于使用其它语言,也会有例外,但不如您想像的那样多。

string 模块包含了几种类型的事物,如函数、方法和类;它还包含了公共常量的字符串。例如:

string 用法例 1

>>>
       
          import
         string
>>> string.whitespace
        '\011\012\013\014\015 '
>>> string.uppercase
        'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
     


虽然可以用手写出这些常量,string 版本或多或少确保了常量对于运行 Python 脚本的国家语言和平台将是正确的。

string 还包括了以常见方式(可以结合这些方式来构成几种罕见的转换)转换字符串的函数。例如:

string 用法例 2

>>>
       
          import
         string
>>> s =
        "mary had a little lamb"
>>> string.capwords(s)
        'Mary Had A Little Lamb'
>>> string.replace(s,
        'little',
        'ferocious')
        'mary had a ferocious lamb'
     


还有许多没有在这里具体说明的其它转换;可以在 Python 手册中查找详细信息。

还可以使用 string 函数来报告字符串属性,如子串的长度或位置,例如:

string 用法例 3

>>>
       
          import
         string
>>> s =
        "mary had a little lamb"
>>> string.find(s,
        'had')5>>> string.count(s,
        'a')4
     


最后,string 提供了非常 Python 化的奇特事物。.split() 和 .join() 对提供了在字符串和字节组之间转换的迅捷方法,您会发现它们非常有用。用法很简单:

string 用法例 4

>>>
       
          import
         string>>> s =
        "mary had a little lamb"
>>> L = string.split(s)
>>> L
[
        'mary',
        'had',
        'a',
        'little',
        'lamb']
>>> string.join(L,
        "-")
        'mary-had-a-little-lamb'
     


当然,除了 .join() 之外,也许会利用列表来做其它事(如某些涉及我们熟悉的 for ... in ... 结构的事情)。




回页首


标准模块:re

re 模块废弃了在老的 Python 代码中使用的 regex 和 regsub 模块。虽然相对于 regex 仍然有几个有限的优点,不过这些优点微不足道,不值得在新代码中使用。过时的模块可能会从未来的 Python 发行版中删除,并且 1.6 版可能有一个改进的接口兼容的 re 模块。所以,规则表达式仍将使用 re 模块。

规则表达式很复杂。也许有人会撰写关于这个主题的书,但实际上,已经有许多人这样做了!本文尝试捕捉规则表达式的“完全形态”,让读者可以掌握它。

规则表达式是一种很简练方法,用于描述可能在文本中出现的模式。是否会出现某些字符?是否按特定顺序出现?子模式是否会重复一定次数?其它子模式是否会排除在匹配之外?从概念上说,似乎不能用自然语言了直观地描述模式。诀窍是使用规则表达式的简洁语法来编码这种描述。

当处理规则表达式时,将它作为它自己的编程问题来处理,即使只涉及一或两行代码;这些行有效地构成了一个小程序。

从最小处着手。从最基本上看,任何规则表达式都涉及匹配特定的“字符类”。最简单的字符类就是单个字符,它在模式中只是一个字。通常,您希望匹配一类字符。可以通过将类括在方括号内来表明这是一个类;在括号中,可以有一组字符或者用破折号指定的字符范围。还可以使用许多命名字符类来确定您的平台和国家语言。以下是一些示例:

字符类

>>>
       
          import
         re
>>> s =
        "mary had a little lamb"
>>>
       
          if
         re.search(
        "m", s):
       
          print
        
        "Match!"
        # char literal
Match!
>>>
       
          if
         re.search(
        "[@A-Z]", s):
       
          print
        
        "Match!"
        # char class
...
        # match either at-sign or capital letter
...
>>>
       
          if
         re.search(
        "\d", s):
       
          print
        
        "Match!"
        # digits class
...
     


可以将字符类看作是规则表达式的“原子”,通常会将那些原子组合成“分子”。可以结合使用 分组和 循环 来完成此操作。由括号表示分组:括号中包含的任何子表达式都被看作是用于以后分组或循环的原子。循环则由以下几个运算符中的某一个来表示:"*" 表示“零或多”;"+" 表示“一或多”;"?" 表示“零或一”。例如,请看以下示例:

样本规则表达式

ABC([d-w]*\d\d?)+XYZ


对于要匹配这个表达式的字符串,它必须以 "ABC" 开头、以 "XYZ" 结尾 -- 但它的中间必须要有什么呢?中间子表达式是 ([d-w]*\d\d?),而且后面跟了“一或多”运算符。所以,字符串的中间必须包括一个(或者两个,或者一千个)与括号中的子表达式匹配的字符或字符串。字符串 "ABCXYZ" 不匹配,因为它的中间没有必要的字符。

不过这个内部子表达式是什么呢?它以 d-w 范围内的 零或多个 字母开头。一定要注意:零字母是有效匹配,虽然使用英语单词 "some"(一些)来描述它,可能会感到很别扭。接着,字符串必须 恰好有一个数字;然后有 零或一个 附加数字。(第一个数字字符类没有循环运算符,所以它只出现一次。第二个数字字符类有 "?" 运算符。)总而言之,这将翻译成“一个或两个数字”。以下是一些与规则表达式匹配的字符串:

匹配样本表达式的字符串

ABC1234567890XYZ
ABCd12e1f37g3XYZ
ABC1XYZ


还有一些表达式与规则表达式 不匹配(想一想,它们为什么不匹配):

不匹配样本表达式的字符串

ABC123456789dXYZ
ABCdefghijklmnopqrstuvwXYZ
ABcd12e1f37g3XYZ
ABC12345%67890XYZ
ABCD12E1F37G3XYZ


需要一些练习才能习惯创建和理解规则表达式。但是,一旦掌握了规则表达式,您就具有了强大的表达能力。也就是说,转而使用规则表达式解决问题通常会很容易,而这类问题实际上可以使用更简单(而且更快速)的工具,如 string,来解决。


参考资料

    您可以参阅本文在 developerWorks 全球站点上的 英文原文.

    Jeffery E. F. Friedl 撰写的 Mastering Regular Expressions (O'Reilly 1997 年出版)是一本关于规则表达式的非常标准且权威性的参考书。

    有关对于仍广泛使用且非常有效的早期文本处理工具的一些好的介绍,请看 Dale Dougherty 和 Arnold Robbins 撰写的 Sed & Awk(O'Reilly 和 Associates 于 1997 年出版)。

    请阅读 mxTextTools ,Python 的快速文本操作工具。

    规则表达式的详细信息:
        Python.org 的规则表达式 how-to 文档
        肯塔基大学的 规则表达式概述 (overview of regular expressions)



关于作者



David Mertz 是近廿年的程序员和作家;但他只写 有关 最新编程的文章(并乐此不疲)。“现实”中的 David Mertz 是名倔强的学者,受利益驱使加入 IT 行业。David Mertz 喜欢在每句话的开头使用同一个词(而且喜欢使用首字母相同的单词)。可以通过 mertz@gnosis.cx 与 David Mertz 取得联系; http://gnosis.cx/publish/ 上刊登了他写的文章。非常欢迎对过去的、这一篇或将来的专栏文章提出意见和建议。
分享到:
评论

相关推荐

    笨办法学.Python.(第三版)

    笨办法学 Python (第三版) 欢迎阅读《笨办法学 Python》第三版。本书中译本发布于 https://learn-python-the-hard-way-zh_cn-translation.readthedocs.org 英文原版地址为 http://learnpythonthehardway.org/book/...

    Learn Python The Hard Way[中文]

    笨办法学 Python (Learn Python The Hard Way) Contents: 译者前言 前言:笨办法更简单 习题 0: 准备工作 习题 1: 第一个程序 习题 2: 注释和井号 习题 3: 数字和数学计算 习题 4: 变量(variable)和命名 ...

    笨办法学Python

    笨办法学Python 译者前言 前言:笨办法更简单 习题 0: 准备工作 习题 1: 第一个程序 习题 2: 注释和井号 习题 3: 数字和数学计算 习题 4: 变量(variable)和命名 习题 5: 更多的变量和打印 习题 6: 字符串...

    本办法学习python

    习题 6: 字符串(string)和文本 习题 7: 更多打印 习题 8: 打印,打印 习题 9: 打印,打印,打印 习题 10: 那是什么? 习题 11: 提问 习题 12: 提示别人 习题 13: 参数、解包、变量 习题 14: 提示和传递 习题 15: ...

    Learn Python the Hard Way(第三版)-带书签.pdf

    习题 6: 字符串 (string) 和文本 习题 7: 更多打印 习题 8: 打印,打印 习题 9: 打印,打印,打印 习题 10: 那是什么? 习题 11: 提问 习题 12: 提示别人 习题 13: 参数、解包、变量 习题 14: 提示和传递 习题 15: ...

    笨办法学python.zip

    "笨办法"学Python(第3版)目录 习题0 准备工作 1 习题1 第一个程序 7 习题2 注释和#号 12 习题3 数字和数学计算 14 习题4 变量和命名 17 习题5 更多的变量和打印 20 习题6 字符串和文本 23 习题7 更多打印 ...

    [笨方法学.Python].(Learn.Python.The.Hard.Way).Zed.Shaw.文字版

    习题 6: 字符串(string)和文本 习题 7: 更多打印 习题 8: 打印,打印 习题 9: 打印,打印,打印 习题 10: 那是什么? 习题 11: 提问 习题 12: 提示别人 习题 13: 参数、解包、变量 习题 14: 提示和传递 习题 15: ...

    FDTDPy:python中的电磁FDTD算法

    使用文本文件中的“eps”和“mu”对象可以轻松构建设备。 可以以数组的形式添加任意数量的阶跃函数:例如: 'eps' : [([100,200], 2),([200,300], 3),([300,400], 4),]给出位置 100-200 相对 eps 2 和 200-300 相对...

    Python的动态重新封装的教程

    让我们描绘一下本文的情节:假设您要在本地机器上运行一个进程,而部分程序逻辑却在另...同样,我偶尔注意到可以用更有效的方法转换某些 ASCII 标记,或者解决了一个在处理某个特殊标记结构中的错误。 事实上,本专栏的

    python-samples:Google适用于Google Workspace API的Python示例

    提取文本:仅提取Google文档的文本 邮件合并:从纯文本或Google表格数据源执行邮件合并 驱动器V3 快速开始 DriveApp :一个简单的应用程序,可将文件上传到Google云端硬盘。 邮箱 快速开始 床单 快速开始 片段 ...

    文本标注工具YEDDA

    YEDDA 是一个简单易用的文本标注工具,其前身是 SUTDAnnotator,该标注工具支持键盘快捷键标注,用户只需选中文本并按快捷键如A,就会自动标注。标注结果用 .ann 文件来保存,可以直接到处序列后的标注结果,十分...

    KusoIDE:基于可爱的 GNUEmacs 的快速灵活的 IDE,适用于 Emacs 大师

    文本信息 git (如果你想通过el-get安装或更新包) bzr(如果您想通过el-get安装或更新软件包) Python 依赖项(kuso-python 插件) pep8 皮片 pychecker 派林特 绝地武士 EPC Ruby 依赖项(kuso-ruby 插件) rb...

    Py.sneaker_webscrape:一个Python脚本,旨在对各种运动鞋相关网站进行文本分析

    Py.sneakernews.webscrape 一个旨在对Sneakernews.com网站进行文本分析的Python脚本

    whimsylib:用于基于文本的游戏的通用游戏引擎

    奇思力受启发的基于文本的游戏的游戏引擎。 这是背后的游戏引擎。开发设置一个virtualenv并安装开发要求。 python3.8 -m venv venvsource venv/bin/activatepip install -r requirements/requirements-dev.txt释放...

    自然语言处理:个人项目

    自然语言处理个人项目:제:존대말,반말인공지능 :speech_balloon:NLP / RNN소개 ①数据:쌍으쌍으로필요한数据모음 up_data_02.csv:1 CSV格式的视频down_data_02.csv:1次更新csv stopword_02.txt:txt文本文件...

    necrodancer-level-translator:一个简单的“关卡编辑器”,可将文本文件转换为用于 NecroDancer 的 Crypt 的 XML 地牢文件 (http

    相反,像这样启动你最喜欢的文本编辑器和设计级别: +x+++x+++x+ x++//////+x ++/////c//+ +/////////+ +///p////++ x///////++x +/+/////+/+ +////+//+/+ +/////c//s+ +/+/////+/+ x///+///+/x +x+++x+++x+ (这...

    tg_crawler:只是基于tg-cli的Telegram凌乱爬虫。 现在已弃用,请使用telegram-export

    聊天记录将保存在SQLite数据库和文本文件中。 您可以使用不同的参数在数据库中查询,例如通道名称,组名称,电报用户名,电报唯一ID等。 适用于Python 3.3+。 依存关系 使用以下命令安装依赖项: pip install -r ...

    百度DeepSpeech架构的TensorFlow实现-Python开发

    DeepSpeech项目DeepSpeech是一个开源语音转文本引擎,使用了基于百度的Deep Speech研究论文的机器学习技术训练的模型。 DeepSpeech项目使用Google的TensorFlow制作Project DeepSpeech项目DeepSpeech是一个开源语音转...

    summary-webpage:一个小的NLP SAAS项目,用于总结一个网页

    Flask应用程序,使用“自然语言处理”提取和汇总网页。 指数 动机 该项目的动机是为文本摘要算法提供可用于生产的API,并将其用于实际的用例。 该项目使用Python实现了NLP算法,并使用flask API提供服务。 如何开始 ...

    acronym_detector:在PubMed上检测首字母缩写词并建议短语

    acronym_detector 在PubMed上检测首字母缩写词并建议短语预处理:有关代码执行中的位置参数的信息,请参见-h /-help。运行四个脚本以将首字母缩写词,词组,计数和...data_to_db.py:从先前的文本文件中获取数据并

Global site tag (gtag.js) - Google Analytics