Python 使用文本
字符串是 Python 中的字符序列,类似于数组和代码,其可以利用一组属性和方法来轻松的对文本数据进操作处理,这使得 Python 称为许多场景中进行文本分析的首选语言。
字符串文字
Python 有各种类型的字符串,以 BNF(Backus-Naur Fornm)为我们提供了如 Python 官方文档中所示的生成字符串的通用词汇定义:
stringliteral ::= [stringprefix](shortstring | longstring)
stringprefix ::= "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR" | "b" | "B" | "br" | "Br" | "bR" | "BR"
shortstring ::= "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring ::= "'''" longstringitem* "'''" | '"""' longstringitem* '"""'
shortstringitem ::= shortstringchar | escapeseq
longstringitem ::= longstringchar | escapeseq
shrtstringchar ::= <any source character execpt "\" or newline or the quote>
longstringchar ::= "\" <any ASCII character>
|
上述规则说明存在不同类型的字符串前缀,可以使用不同的字符类型来生成字符串文字。简单地说,下列类型的字符串使用最多。
- 短字符串(short string):这些字符串通常用单个( ' ) 或者双引号( " ) 把字符串括起来。例如 'Hello' 和 " Hello"。
- 长字符串(long string):这些字符串通常用三个单个( ''' ) 或三个双引号( """ ) 把字符括起来。例如 """ Hello, I'm a long string“”“ 或者 '''Hello I\'m a long string '''。注意( \ ) 表示下面所讨论的转义序列。
- 字符串转义序列(escape sequences in strings): 这些字符串通常具有嵌入的转义序列,其中转义序列的规则以反斜杠 ( \ ) 开始,随后是任意的 ASCII 字符。因此,它们执行行退格插补。流行的转义序列包括 (\n) 表示新行的字符, 和 ( \t ) 表示是一个 tab。
- 字节(bytes): 用来表示字符串(bytestring), 从而创建数据类型 bytes 的对象。这些字符串可以创建为 bytes ('... '),或使用 b'...' 表示。例如 bytes('hello') 和 b'hello'。
- 原始字符串(raw strings): 这些字符串最初专门用于正则表达式(regex) 和创建 regex 模式。这些字符串可以使用 r'...' 表示法创建,并将字符串保持为原始或原生形式。因此,它不执行任何退格插补,并关闭了转义序列。例如: r'Hello'。
- Unicode:这些字符串在文本中支持 Unicode 字符,通常是非 ASCII 字符序列。字符串用 u‘... ’ 表示。除了字符串表示之外,还有几种具体的方式来表示字符串中的特殊 Unicode 字符。通常包括十六进制字符值转义序列,其中第一个格式使用 4 个十六进制数字来编码 16 位字符,第二个格式使用 8 个十六位数字来编码 32 位字符。例如 u'H\xe811o' 和 u'\u00e8llo',表示字符串 'Hèllo'。
- 以下代码段描述了这些不同类型的字符串及其输出:
In [ 3 ]: simple_string = 'hello' + " I'm a simple string"
In [ 4 ]: print (simple_string)
hello I'm a simple string
|
In [ 5 ]: multi_line_string =
In [ 6 ]: multi_line_string
Out[ 6 ]: "Hello I'm\na multi-line\nstrings!"
In [ 7 ]: print (multi_line_string)
Hello I'm
a multi - line
strings!
|
In [ 10 ]: escaped_string = "C:\the_folder\new_dir\file.txt"
In [ 11 ]: print (escaped_string)
C: he_folder
ew_dir
ile.txt
|
In [ 12 ]: raw_string = r 'C:\the_folder\new_dir\file.txt'
In [ 13 ]: print (raw_string)
C:\the_folder\new_dir\ file .txt
|
In [ 14 ]: string_with_unicode = u 'H\u00e8llo!'
In [ 15 ]: print (string_with_unicode)
Hèllo
|
字符串操作和方法
字符串可迭代的序列,这意味着可以用它们执行大量操作,特别是当将文本数据处理和解析为易于使用(easy-to-consume) 的格式时尤其有用。可以对字符串执行几种操作,它们分类为以下几个部分:
- 基本操作。
- 索引和分片。
- 方法。
- 格式化。
- 正则表达式。
这些将涵盖使用字符串时最常用的技术。
1、基本操作
可以对字符串执行几个基本操作,包括连接和检查字符串、字符和长度。以下代码段通过一些实例说明了这些操作:
In [ 20 ]: 'Hello' + ' and welcone ' + 'to Python!'
Out[ 20 ]: 'Hello and welcone to Python!'
In [ 21 ]: 'Hello' ' and welcome ' 'to Python!'
Out[ 21 ]: 'Hello and welcome to Python!'
|
In [ 22 ]: s1 = 'Python!'
In [ 23 ]: 'Hello ' + s1
Out[ 23 ]: 'Hello Python!'
In [ 24 ]: 'Hello Python!'
Out[ 24 ]: 'Hello Python!'
In [ 25 ]: 'Hello ' s1
File "<ipython-input-25-f8cd4e64d843>" , line 1
'Hello ' s1
^
SyntaxError: invalid syntax
|
In [ 28 ]: s2 = '--Python--'
In [ 29 ]: s2 * 5
Out[ 29 ]: '--Python----Python----Python----Python----Python--'
In [ 30 ]: s1 + s2
Out[ 30 ]: 'Python!--Python--'
In [ 31 ]: (s1 + s2) * 3
Out[ 31 ]: 'Python!--Python--Python!--Python--Python!--Python--'
|
In [ 32 ]: s3 = ( 'This '
...: 'is another way '
...: 'to concatenate '
...: 'several strings!' )
In [ 33 ]: s3
Out[ 33 ]: 'This is another way to concatenate several strings!'
|
In [ 36 ]: 'way' in s3
Out[ 36 ]: True
In [ 37 ]: 'python' in s3
Out[ 37 ]: False
|
In [ 38 ]: len (s3)
Out[ 38 ]: 51
|
2、索引和切片
如前所述,字符串是可迭代对象,有序字符的序列。因此,字符串可以与其他可迭代对象(例如列表)类似的进行索引、切片和迭代。在字符串中,每个字符串都有一个特定的位置,称为它的索引(index)。使用索引,就可以访问字符串的指定部分。使用字符串中的的定位置或索引访问单个字符称为索引(indexing),而访问字符串的的一部分。一种是非 0 开始,每一个字符每一次增加1,知道字符串的结尾。另一种是从字符串末尾的 -1 开始,每个字符每次减 1,知道字符串的开头。如下图字符串 'PYTHON' 的两种索引类型。
![](https://wiki.shileizcc.com/confluence/download/attachments/42533082/image2018-9-3_14-17-21.png?version=1&modificationDate=1535955441000&api=v2)
要访问字符串中的任何特定字符,必须使用相应的索引,可以使用语法 var[start: stop] 来提取切片,该语法索取字符串 var 中从索引 start 知道索引 stop 的所有字符,但不包括位于 stop 索引之上的字符。
以下示例显示如对字符串进行索引、切片和迭代:
In [ 45 ]: for index, character in enumerate (s):
...: print ( 'Character' , character + ':' , 'hes index:' , index)
Character P: hes index: 0
Character Y: hes index: 1
Character T: hes index: 2
Character H: hes index: 3
Character O: hes index: 4
Character N: hes index: 5
|
In [ 46 ]: s[ 0 ], s[ 1 ], s[ 2 ], s[ 3 ], s[ 4 ], s[ 5 ]
Out[ 46 ]: ( 'P' , 'Y' , 'T' , 'H' , 'O' , 'N' )
In [ 47 ]: s[ - 1 ], s[ - 2 ], s[ - 3 ], s[ - 4 ], s[ - 5 ], s[ - 6 ]
Out[ 47 ]: ( 'N' , 'O' , 'H' , 'T' , 'Y' , 'P' )
|
In [ 48 ]: s[:]
Out[ 48 ]: 'PYTHON'
In [ 49 ]: s[ 1 : 4 ]
Out[ 49 ]: 'YTH'
In [ 50 ]: s[: 3 ]
Out[ 50 ]: 'PYT'
In [ 51 ]: s[ 3 :]
Out[ 51 ]: 'HON'
In [ 53 ]: s[ - 3 :]
Out[ 53 ]: 'HON'
In [ 54 ]: s[: 3 ] + s[ 3 :]
Out[ 54 ]: 'PYTHON'
In [ 55 ]: s[: 3 ] + s[ - 3 :]
Out[ 55 ]: 'PYTHON'
|
In [ 56 ]: s[:: 1 ]
Out[ 56 ]: 'PYTHON'
In [ 57 ]: s[:: 2 ]
Out[ 57 ]: 'PTO'
|
In [ 58 ]: s[ 0 ] = 'X'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeError Traceback (most recent call last)
<ipython - input - 58 - 68d9ab99b09c > in <module>()
- - - - > 1 s[ 0 ] = 'X'
TypeError: 'str' object does not support item assignment
|
In [ 59 ]: 'X' + s[ 1 :]
Out[ 59 ]: 'XYTHON'
|
3、方法
字符串和 Unicode 提供了一个庞大的内置方法(method),可用于对字符串执行各种转换、控制和操作。详细讨论每个方法将超出当前的范围,在 https://docs.python.org/2/library/stdtypes.html#string-methods 上的官方 Python 文档提供了所需的每个方法的所有信息,以及语法和定义。方法是非常有用的,能提高工作效率,因为必须在花费额外的时间编写模板代码来处理和操作字符串。
以下代码展示了一些流行的字符串操作方法示例:
In [ 61 ]: s.capitalize()
Out[ 61 ]: 'Python is great'
In [ 62 ]: s.upper()
Out[ 62 ]: 'PYTHON IS GREAT'
|
In [ 63 ]: s.replace( 'python' , 'analytics' )
Out[ 63 ]: 'analytics is great'
|
In [ 64 ]: s = 'I,am,a,comma,separated,string'
In [ 65 ]: s.split( ',' )
Out[ 65 ]: [ 'I' , ' am' , 'a' , 'comma' , 'separated' , 'string' ]
In [ 66 ]: ' ' .join(s.split( ',' ))
Out[ 66 ]: 'I am a comma separated string'
|
In [ 68 ]: s = ' I am surrounded by spaces '
In [ 69 ]: s
Out[ 69 ]: ' I am surrounded by spaces '
In [ 70 ]: s.strip()
Out[ 70 ]: 'I am surrounded by spaces'
|
In [ 71 ]: s = 'this is in lower case'
In [ 72 ]: s.title()
Out[ 72 ]: 'This Is In Lower Case'
|
前面的例子中,对于许多可能用于控制和操作字符串的介绍仅仅是浅尝机制。
4、格式化
字符串的格式化(formatting)用于替换字符串中的特定数据对象和类型。当向用户显示文本时,格式化最常用。字符串主要有两种不同的类型的格式化:
- 格式化表达式(formatting experssions):这些表达式通常的语法是 '...%s...%s...' % (values),其中 %s 表示占位符用于从 values 中描述的字符串列表中替换字符串的占位符。这与 C 语法风格的 printf 模块非常先死,Python 自始至今都保留着。可以用 % 符号加上后面的想用字母来替换其他类型的值,如整数的 %d 和浮点数的 %f。
- 格式化方法(formatting methods):这些字符串采用 '...{}...{}...'.format(values)的形式,其使用大括号 {} 作为占位符,通过 format 方法从 values 中放置字符串。Python 子 2.6.x 版本只来,这个方法一直存在。
下面的代码段使用了几个示例标书了两种类型的字符串格式化:
In [ 73 ]: 'Hello %s' % ( 'Python!' )
Out[ 73 ]: 'Hello Python!'
In [ 74 ]: 'Hello %s' % ( 'World!' )
Out[ 74 ]: 'Hello World!'
|
In [ 75 ]: 'We have %d %s containing %.2f gallons of %s' % ( 2 , 'bottles' , 2.5 , 'milk' )
Out[ 75 ]: 'We have 2 bottles containing 2.50 gallons of milk'
In [ 76 ]: 'We have %d %s containing %.2f gallons of %s' % ( 5 , 'jugs' , 1 - . 867 , 'juice' )
Out[ 76 ]: 'We have 5 jugs containing 0.13 gallons of juice'
|
In [ 77 ]: 'Hello {} {},it is a great {} to meet you' . format ( 'Mr.' , 'Jones' , 'pleasure' )
Out[ 77 ]: 'Hello Mr. Jones,it is a great pleasure to meet you'
In [ 78 ]: 'Hello {} {},it is a great {} to meet you' . format ( 'Sir' , 'Arthur' , 'honor' )
Out[ 78 ]: 'Hello Sir Arthur,it is a great honor to meet you'
|
In [ 79 ]: 'I have a {food_item} and a {drink_item} with me' . format (drink_item = 'soda' , food_item = 'sandwich' )
Out[ 79 ]: 'I have a sandwich and a soda with me'
In [ 80 ]: 'The {animal} has the following attributes: {attributes}' . format (animal = 'dog' , attributes = [ 'lazy' , 'loyal' ])
Out[ 80 ]: "The dog has the following attributes: ['lazy', 'loyal']"
|
从上述实例中,可以看到格式化字符串并没有硬性规定,因此可以继续尝试使用不同的格式。
5、正则表达式
正则表达式(regular expressions)也称为 regexes,允许你创建字符串格式,并使用它们来搜搜和替换文本数据中的特定匹配模式。Python 提供了一个名为 re 的富模块,用于创建和使用正则表达式。虽然它易用,但很难掌握。
正则表达式是通过使用原始字符串符号表示的特定模式。这些模式基于模式表达式规则与特定的一组字符串相匹配。然后,这些模式通常被编译成字节码,在通过使用匹配的引擎执行匹配的字符串。re 模块还提供了几个可以改变模式匹配执行方式的只是(flag)参数。一些重要的表示参数包括以下一个内容:
- re.I 或 re.IGNORECASE 用于匹配忽略区分大小写的模式。
- re.S 或 re.DOTALL 使句点 ( . ) 字符匹配包括新行的任何字符。
- re.U 或 re.UNICODE 有助于匹配基于 Unicode 的字符 (在 Python 3.x 中不推荐使用)。
对于模式匹配,在正则表达式中使用了各种各样的规则。一些流行的规则如下:
- . 用于匹配任意的单个字符。
- ^ 用于匹配字符串的首字符。
- $ 用于匹配字符串的末尾字符。
- * 用于在模式中的 * 符号之前,匹配之前所述正则表达式的零个或多个情况。
- ? 用于在模式中的 ? 符号之前,匹配之前所述正则表达式的零个或者一个情况。
- [...] 用于匹配方括号内的任意一组字符。
- [^...] 用于匹配在方括号中 ^ 字符之后不存在的一个字符。
- | 表示 OR 运算符,用于匹配前一个或下一个字符表达式。
- + 用于在模式中的 + 符合之前,匹配之前所述正则表达式的一个或多个情况。
- \d 用于匹配十进制数字,也描述为 [0-9]。
- \D 用于匹配非数字,也描述为 [^0-9]。
- \s 用于匹配空字符。
- \S 用于匹配非空格字符。
- \w 用于匹配字母数字字符,也描述为 [ a-zA-Z0-9_ ]。
- \W 用于匹配非字母数字字符,也描述为 [ ^a-zA-Z0-9_ ]。
正则表达式可以编译为模式对象,然后使用各种方法对字符串进行模式搜索和替换。 re 模块提供执行这些操作的主要方法,如下所示。
- re.compile():该方法将指定的正则表达式模式编译为可用于匹配和搜索的正则表达式对象。如前所述,需要采用一个模式和可选标识作为输入参数。
- re.match():该方法用于匹配字符串开始的模式。
- re.search():该方法用于匹配出现在字符串中任意位置的模式。
- re.findall():该方法呢返回字符串中对指定的正则表达式模式的所有费重叠匹配项。
- re.finditer():当从左到右扫描时,该方法以跌点形式返回字符串中特定模式的所有配实例。
- re.sub():该方法用于以字符串来替代字符串中指定的正则表达式模式。它仅仅替换字符串中最左出现的模式。
以下代码段描述了刚才讨论的一些方法,以及在处理字符串和正则表达式时通常使用的步骤:
In [ 82 ]: s = u 'H\u00e8llo'
In [ 83 ]: s
Out[ 83 ]: 'Hèllo'
In [ 84 ]: print (s)
Hèllo
|
In [ 85 ]: re.findall(r '\w+' , s)
Out[ 85 ]: []
|
In [ 93 ]: re.findall(r '\w+' , s, re. UNICODE )
Out[ 93 ]: [ 'Hèllo' ]
|
In [ 94 ]: pattern = 'python'
In [ 95 ]: s1 = 'Python is an excellent language'
In [ 96 ]: s2 = 'I love the Python language. I also use Python to build applications at work!'
|
In [ 97 ]: re.match(pattern, s1)
In [ 98 ]: re.match(pattern, s1, flags = re.IGNORECASE)
Out[ 98 ]: <_sre.SRE_Match object ; span = ( 0 , 6 ), match = 'Python' >
In [ 102 ]: print ( 'Found match {} ranging form index {} - {} in the string "{}"' . format (m.group( 0 ), m.start(), m.end(), s1))
Found match Python ranging form index 0 - 6 in the string "Python is an excellent language"
|
In [ 105 ]: re.match(pattern, s2, re.IGNORECASE)
|
In [ 106 ]: re.search(pattern, s2, re.IGNORECASE)
Out[ 106 ]: <_sre.SRE_Match object ; span = ( 11 , 17 ), match = 'Python' >
In [ 107 ]: re.findall(pattern, s2, re.IGNORECASE)
Out[ 107 ]: [ 'Python' , 'Python' ]
In [ 108 ]: match_objs = re.finditer(pattern, s2, re.IGNORECASE)
In [ 109 ]: print ( "string:" , s2)
string: I love the Python language. I also use Python to build applications at work!
In [ 110 ]: for m in match_objs:
...: print ( 'Found match {} ranging form index {} - {}' . format (m.group( 0 ), m.start(), m.end()))
...:
Found match Python ranging form index 11 - 17
Found match Python ranging form index 39 - 45
|
In [ 112 ]: re.sub(pattern, 'Java' , s2, flags = re.IGNORECASE)
Out[ 112 ]: 'I love the Java language. I also use Java to build applications at work!'
In [ 113 ]: re.subn(pattern, 'Java' , s2, flags = re.IGNORECASE)
Out[ 113 ]: ( 'I love the Java language. I also use Java to build applications at work!' , 2 )
|
字符串形成处理文本的基础,这是文本分析中的重要组成内容。
文本分析框架
Python 生态系统非常多样化,支持许多利用中各种各样的库、框架和模块。因为要将分析文本数据并对其进行各种操作,所以你需要了解专用的框架和分本分析库,可以安装和开始使用它们,就像 Python 标准库中的任何其他内置模块一样。这些框架已经存在很长一段时间,包含各种方法、功能和特定,用于文本上操作,以获取洞察力,并为进一步的分析做好数据准备,例如对预处理后的文本数据应用机器学习算法。
利用这些框架可以节省大量的精力和时间,否则在编写样板代码来加工、处理和操作文本数据时将花费很多时间。因此,这些框架可使开发人员和研究人员能更多地关注解决实际问题以及这样做所需的必要逻辑和算法。以下列出了一些最流行的文本分析库和框架。
- NLTK:该自然语言工具包是一个包含 50 多个资料库和词汇资源的完整平台。它还提供必要的工具、接口和方法来处理和分析文本数据。
- pattern:pattern 项目开始于比利时安特卫普大学计算语言与心理语言研究中心的研究项目。它为 Web 挖掘、信息检索、NLP、机器学习和网络分析提供了工具和接口。pattern.en 模块包含文本分析的大多数实用工具。
- gensim:gensim 库具有一套丰富的语义分析功能,包括主题建模和相似性分析。而且最重要的是包含一个谷歌非常流行的 word2vec 模型(最初可用作 C 语言包)的 Python 接口,这个神经网络模式实现了学习词语的分布式表达,其中相似词(语义)彼此邻近出现。
- textblob:它是另一个提供多种功能的库,包括文本处理。短语提取、分类、POS 标注、文本翻译和情感分析。
- spacy:这是一个教新的库,它声称通过每种技术和算法的最佳实现来提供工业级 NLP 功能,是的 NLP 任务在性能和实现方面高效。
除了这些,还有其他几个不是专门用于文本分析的框架和库,但是相对文本数据使用机器学习技术时,还是这些框架和库还是有用的。以上这些库包括 scikit-learn、numpy 和 scipy stack。除此之外,如果想要构建基于神经网络、ConvNet 和基于 LSTM 的模型的高度深度学习(deep learning)模型,深度学习和基于张量的库如 theano、tensorflow 和 keras 也会用得上的。