Python文本处理(三)unicodedata & stringprep & readline模块

unicodedata模块

unicodedata模块提供对Unicode字符数据库(UCD)的访问,该数据库为所有Unicode字符定义字符属性,数据库中包含的数据从UCD 9.0.0版编译而来。unicodedata模块使用的名称和符号与Unicode#44标准附件一致。

unicodedata模块定义的函数如下:

unicodedata.lookup()

​ unicodedata.lookup(name)函数是按名称查找字符,如果找到具有给定名称的字符,则返回相应的字符,若未找到,则引发KeyError错误。Python3.3之后,添加了对名称别名和命名序列的支持。

unicodedata.name()

​ unicodedata.name(chr, default)函数返回分配给字符chr的名称作为字符串,如果没有定义这样的值,则返回默认值,如果没有给出默认值个会引发ValueError。

unicodedata.decimal()

​ unicodedata.decimal(chr, default)返回分配给字符chr的十进制作为整数。如果没有定义这样的值,则返回defalut,如果没有给出默认值,则会引发ValueError。

unicodedata.digit()

​ unicodedata.digit(chr, default)返回分配给字符chr的数字值作为整数,如果没有定义这样的值,则返回默认值defalut,如果没有给出defalut,则会引发ValueError。

unicodedata.numeric()

​ unicodedata.numeric(chr, default)返回分配给字符chr的数值作为浮点数,如果值没有被定义,则返回默认值default,如果没有设定默认值,则会引发ValueError。

unicodedata.category()

​ unicodedata.category(chr)返回分配给字符chr的常规类别为字符串。

unicodedata.bidirectional(chr)

​ unicodedata.bidirectional(chr)返回分配给字符chr的双向类作为字符串,如果未定义此类值,则返回空字符串。

unicodedata.combining()

​ unicodedata.combining(chr)返回分配给字符chr的规范组合类作为整数,如果没有定义组合,则返回0。

unicodedata.east_asian_width()

​ unicodedata.east_asian_width(chr)返回分配给字符chr的宽度。

unicodedata.mirrored()

​ unicodedata.mirrored(chr)返回分配给字符chr的镜像属性为整数,如果字符在双向文本中被识别为“镜像”字符,则返回 1 ,否则返回 0

unicodedata.decomposition()

​ unicodedata.decomposition(chr) 以字符串形式返回分配给字符chr的字符分解映射,如果未定义此类映射,则返回空字符串。

unicodedata.normalize(form, unistr)

​ unicodedata__normalize__(form, unistr)返回unicode字符串unistr的规范形式。form的有效值为NFCNFKC、“NFD”和“NFKD”。

​ 对于每个字符,有两种规范形式:规范形式C和规范形式D。规范形式D(NFD)也称为规范分解,将每个字符转换为其分解形式。规范形式C(NFC)首先应用规范分解,然后再次组合预组合字符。除了这两种形式之外,还有另外两种基于兼容性等效的正常形式。除了这两种形式之外,还有另外两种基于兼容性等效的正常形式。在Unicode中,支持某些字符与其它格式统一组成的字符,例如,u+2160(罗马数字1)实际上与u+0049(拉丁文大写字母I)相同,为了与现有字符集(如GB2312)兼容,Unicode支持这种形式的字符。标准形式KD(NFKD)将应用兼容性分解,即将所有兼容性字符替换为它们的等效字符。标准形式KC(NFKC)首先应用兼容性分解,然后是规范组合。

​ 即使对两个Unicode字符串进行了规范化处理,表面上看上去相同,但如果一个字符串具有组合字符,而另一个字符串不具有组合字符,则它们之间的比较可能并不相等。

除了提供的功能函数之外,unicodedata还提供了属性:

unicodedata.unidata_version

​ unicodedata.unidata_version 该属性代表模块中使用的Unicode数据库的版本号

unicodedata.ucd_3_2_0

​ unicodedata.ucd_3_2_0 这是一个对象,其方法与整个模块相同,但对需要此特定版本的Unicode数据库(如IDNA)的应用程序使用Unicode3.2版本数据库。

unicodedata模块应用示例:

>>> import unicodedata
>>> unicodedata.lookup('LEFT CURLY BRACKET')
'{'
>>> unicodedata.name ('/')
'SOLIDUS'
>>> unicodedata.decimal('8')
8
>>> unicodedata.category('A')
'Lu'
>>> unicodedata.bidirectional('\u0660')
'AN'

stringprep模块-处理Intnet字符

stringprep主要针对互联网字符处理的模块。在互联网上识别事物(如主机名)时,通常需要比较这些标识以判断是否相等,具体执行比较的方式后的结果可能取决于应用程序域,例如,它是否应该不区分大小写,可能还需要限制可能的标识,或只允许包含“可打印”字符的标识。

RFC 3454 制定了网络协议中Unicode字符串的预备过程。在将字符串传递到导线上之前,将使用预备过程对其进行处理,处理成规范化的形式。RFC定义了一组表,这些表可以组合成概要文件。每个概要文件必须定义它使用的表,以及stringprep过程的其他可选部分。stringprep配置文件的一个示例是NamePrep,它用于国际化域名。

stringprep模块只公开来自RFC3454的表,由于这些表若用字典dic或列表list表示会非常大,因此模块在内部使用Unicode字符数据库,模块源代码本身是使用mkstringprep.py实用程序生成的。

​ 基于以上原因,这些表作为函数公开,而不是作为数据结构公开。RFC中有两种表:集合映射。对于集合,stringprep提供征函数(如果参数是集合的一部分,则返回true的函数)。对于映射,模块提供了映射函数:给定键,返回关联的值。

​ 以下是stringprep模块提供的可用列表(函数表示):

stringprep列表

stringprep.in_talbe_a1(code)

​ 确定代码是否在表A.1中(Unicode 3.2中的未分配代码点)。


stringprep.in_table_b1(code)

确定代码是否在表B.1中(通常映射为无)


stringprep.map_table_b2(code)

​ 根据表B.2返回code映射的集合值(与NFKC一起使用折叠映射)


stringprep.map_table_b3(code)

​ 根据表B.3返回code映射的集合值(用于不进行规范化的案例折叠的映射)


stringprep.in_table_c_11(code)

​ 确定代码是否在表C.1.1中(ASCII空格字符)


stingprep.in_table_c12(code)

​ 确定代码是否在表C.1.2中(没有ASCII空格字符)


stringprep.in_table_c11_c12(code)

​ 确定代码是否在表C.1中(空格字符,C.1.1和C.1.2的联合)


stringprep.in_table_c21(code)

​ 确定代码是否在表C.2.1中(ASCII 控制字符)


stringprep.in_table_c22(code)

​ 确定代码是否在表C.2.2中(没有控制字符)


stringprep.in_table_c21_c22(code)

​ 确定代码是否在表C.2中(控制字符, 表的C.2.1和C.2.2的联合)


stringprep.in_table_c3(code)

​ 确定代码是否在表C.3中(私有使用)


stringprep.in_table_c4(code)

​ 确定代码是否在表C.4中(非字符代码点)


stringprep.in_table_c5(code)

​ 确定代码是否在表C.5中(替代码)


stringprep.in_table_c6(code)

​ 确定代码是否在表C.6中(不适用于纯文本)


stringprep.in_table_c7(code)

​ 确定代码是否在表C.7中(不适合规范表示)


stringprep.in_table_c8(code)

​ 确定代码是否在表C.8中(更改显示属性或已弃用)


stringprep.in_table_c9(code)

​ 确定代码是否在表C.9中(标记字符)


stringprep.in_table_d1(code)

​ 确定代码是否在表D.1中(具有双向属性“R”或“AL”的字符)


stringprep.in_table_d2(code)

​ 确定代码是否在表D.2中(具有双向属性“L”的字符)

readline模块 - GNU readline接口

readline模块模块定义了许多函数,以便于从Python解释器完成历史文件的读写。模块可以直接使用,也可以通过rlcompleter模块使用,后者支持在交互提示下完成Python标识符。使用此模块进行的设置会影响解释器的交互提示和内置input()函数提供的提示的行为。

​ 底层的readline库API可以由libedit库而不是gnu readline实现。在MacOS X上,readline模块检测运行时使用的库。libedit的配置文件与gnu readline的配置文件不同,如果以编程方式加载配置字符串,则可以检查readline中的文本“libedit”。要区分gnu readlinelibedit,使用doc

Init file 初始化文件

以下函数与init文件和用户配置有关:

pares_and_bind()

​ readline.parse_and_bind(string)

​ 执行字符串参数中提供的init行,调用底层库中的rl_parse_and_bind()函数

read_init_file()

​ readline.read_init_file(filename)

​ 执行readline初始化文件,默认文件名是使用的最后一个文件名,会调用底层库中的rl_read_init_file()函数。

Line buffer

以下功能在line buffer 行缓冲器上运行:

get_line_buffer()

​ readline.get_line_buffer()

​ 返回行缓冲区的当前内容(底层库中的rl_line_buffer)

insert_text()

​ readline.insert_text(string)

​ 在光标位置将文本插入行缓冲区。这将调用底层库中的rl_insert_text(),但忽略返回值

redisplay()

​ readline.redisplay()

​ 更改屏幕上显示的内容以反映行缓冲区的当前内容, 调用底层库中的rl_redisplay()函数

History file

​ 以下功能在历史文件基础上操作执行:

read_history_file()

​ readline.read_history_file(filename)

​ 加载一个readline历史文件,并将其附加到历史列表中,默认文件名为~/.history。这将调用底层库中的read_history()函数

write_history_file()

​ readline.write_history_file(filename)

​ 将历史记录列表保存到历史文件中,覆盖任何现有的文件,默认文件名为~/.history,调用底层库write_history()

append_history_file()

​ readline.append_history_file(filename)

​ 将历史记录的最后一项附加到文件(文件必须已经存在)中,默认文件名为~/.history,会调用底层库的append_history()函数,只有为支持该版本的函数库编译了python时,该函数才存在。

get_history_length()

​ readline.get_history_length()

​ 获得历史文件内容的行数。

set_history_length()

​ readline.set_history_length(length)

​ 设置或返回要保存在历史文件中的所需行数。write_history_file()函数通过调用底层库中的history_truncate_file(),使用此值截断历史文件。负值表示历史文件大小不受限制。

History list

以下函数在全局历史记录列表上操作:

clear_history()

​ readline.clear_history()

​ 清空当前的历史,底层调用clear_history(),只有为支持该版本的函数库编译了Python时,该函数才存在。

get_current_history_length()

​ readline.get_current_history_length()

​ 返回当前存在的历史数据的项目数,这有别于返回当前历史文件数据所需行数的get_historty_length()

get_history_item()

​ readline.get_history_item(index)

​ 返回索引index处历史项的当前内容,项目索引是从1开始,底层库中会调用history_get()

remove_history_item()

​ readline.remove_history_item(pos)

​ 从历史记录中删除由pos指定位置的历史纪录项,位置是从0开始,底层库中会调用remove_history()

replace_history_item()

​ readline.replace_history_item(pos, line)

​ 用line替换由pos指定位置的历史纪录项,位置是从0开始,调用底层库的replace_history_entry()函数

add_history()

​ readline.add_history(line)

​ 向历史纪录缓存器history buffer中追加指定的line,追加到最后一行,会调用底层库中的add_history()

set_auto_history()

​ readline.set_auto_history(enabled)

​ 设置当通过readline读取输入时,启动或禁用_history()的自动调用,enabled是一个bool值,如果为True,则启用自动历史记录;如果为False,则禁用自动历史记录。

​ 不过在Python3.6版本之后,默认设置为启动自动历史纪录,对某个历史记录的更改不会在多个会话中持续。

Starup hooks

​ 以下功能函数工组在 strapup hooks 启动钩子文件上:

set_starup_hook()

​ readline.set_starup_hook(function) 设置或删除由底层库的rl_startup_hook回调调用的函数,如果指定了函数,它将用作新的钩子函数;如果省略或不指定,则删除已安装的任何函数。如果调用 启动钩子在readline打印第一个提示之前,则调用函数不带任何参数。

set_pre_input_hook__()

​ readline.set_pre_input_hook(function)设置或删除由底层库的rl_pre_input_hook回调调用的函数。如果指定了函数,它将用作新的钩子函数;如果省略或不指定,则删除已安装的任何函数。如果调用钩子的时机在打印第一个提示之后且readline开始读取输入字符之前,则调用的时候不带任何参数。只有在版本支持该函数并且编译了python时,该函数才存在。

Completion - 补全机制

​ 以下函数与实现自动补全相关,通常由tab键操作,按tab键进行补全,可以建议并自动完成正在键入的单词。默认情况下,readline设置为由rlcompleter用于完成交互式解释器的python标识符。如果readline模块要与自定义完成符一起使用,则应设置一组不同的单词分隔符。

set_completer()

​ readline.set_completer(function) 设置或删除完成功能。如果指定了函数,将指定的函数新的新的完成器函数;如果省略或不指定,则删除已安装的任何完成器函数。completer函数被作为文本状态函数调用,用于0、1、2……中的状态,直到它返回一个非字符串值。从文本开始返回下一个完成状态。

​ 已安装的完成器函数由传递给底层库rl_completion_matches()entry_func 回调调用。文本字符串来自底层库的rl_attempted_completion_function回调的第一个参数。

get_completer()

​ readline.get_completer()

​ 获取completer函数,如果未设置completer函数,则不获取。

get_completion_type()

​ readline.get_completion_type()

​ 获取正在尝试完成的类型,以整数形式返回基础库中的rl_completion_类型变量。

get_begidx()

​ readline.get_begidx()

​ 获取完成范围的开始索引。索引是传递给底层库rl_attempted_completion_function回调的开始参数。

get_endidx()

​ readline.get_endidx()

​ 获取完成范围的结束索引。索引是传递给底层库rl_attempted_completion_function回调的结束参数。

set_completer_delims()

​ readline.set_completer_delims(string)

​ 设置要完成的单词分隔符。单词分隔符决定了要完成的单词的开头(完成范围),需要访问底层库中的rl_completer_word_break_characters变量 。

get_completer_delims()

​ readline.get_completer_delims()

​ 获取要完成的单词分隔符。单词分隔符决定了要完成的单词的开头(完成范围),需要访问底层库中的rl_completer_word_break_characters变量 。

set_completion_display_matches_hook()

​ readline.set_completion_display_matches_hook(function)

​ 设置或删除完成显示功能,如果指定了函数,指定的函数用作新的完成显示函数;如果省略或不指定,则删除已安装的任何完成显示函数。这将设置或清除底层库中的rl_completion_display_matches_hook回调。每次需要显示匹配的时候,完成显示函数作为function(substitution, [matches], longest_match_length)调用。

readline使用综合示例

>>> #demo 演示如何使用readline模块的历史读取和写入功能从用户的主目录自动加载和保存名为.python_history的历史文件,以下代码通常在用户的pythonstartup文件的交互会话期间自动执行。当以交互模式运行python时,此代码实际上是自动运行的(请参见readline配置)。
>>> import atexit
>>> import os
>>> import readline
>>> histfile = os.path.join(os.path.expanduser('~'), '.python_history')
>>> try:
    readline.read_history_file(histfile)
    # default history len is -1 (infinite), which may grow unruly
    readline.set_history_length(1000)
except FileNotFoundError:
    pass

>>> atexit.register(readline.write_history_file, histfile)
<built-in function write_history_file>
>>> 
>>> #下面的示例实现了相同的目标,但只通过附加新的历史记录来支持并发的交互式会话。
>>> import atexit
>>> import os
>>> import readline
>>> histile = os.path.join(os.path.expanduser('~'), '.python_history')
>>> try:
    readline.read_history_file(histfile)
    h_len = readline.get_current_history_length()
except FileNotFoundError:
    open(histfile, 'wb').close()
    h_len = 0


>>> def save(prev_h_len, histfile):
    new_h_len = readling.get_current_history_length()
    readline.set_history_length(1000)
    readline.append_history_file(new_h_len - prev_h_len, histfile)


>>> atexit.register(save, h_len, histfile)
<function save at 0x10b795e18>
>>> #下面的示例扩展了code.InteractiveConsole类以支持历史记录保存/还原
>>> import atexit
>>> import code
>>> import os
>>> import readline
>> class HistoryConsole(code.InteractiveConsole):
    def __init__(self, locals=None, filename="<console>",
                 histfile=os.path.expanduser("~/.console-history")):
        code.InteractiveConsole.__init__(self, locals, filename)
        self.init_history(histfile)

    def init_history(self, histfile):
        readline.parse_and_bind("tab: complete")
        if hasattr(readline, "read_history_file"):
            try:
                readline.read_history_file(histfile)
            except FileNotFoundError:
                pass
            atexit.register(self.save_history, histfile)

    def save_history(self, histfile):
        readline.set_history_length(1000)
        readline.write_history_file(histfile)


>>> 

rlcompleter ——GNU readline的完成函数

rlcompeleter 通过补全有效的 Python 标识符和关键字为 readline模块定义了一个补全功能。rlcompleter模块是为了使用 Python 的 交互模式而设计的. 除非 Python 是通过-S选项运行, 这个模块总是自动地被导入且配置。

>>> import rlcompleter
>>> import readline
>>> readline.parse_and_bind('tab: complete')
>>>#输入readline.之后按tab键
>>> readline.add_history
<built-in function add_history>

Completer对象

​ 当此模块在具有可用的 readline模块的 Unix 平台被导入, 一个 Completer 实例将被自动创建并且它的 complete() 方法将设置为readline的补全器。

​ Completer对象具有下面的方法:

​ Completer.complete(text, state)

​ 为text返回state补全。 如果text不包含句点符号,函数将从当前定义的名称中完成__main ____builts__keywords。如果为加点的名称执行调用,它将尝试尽量求值直到最后一部分为止而不产生附带影响(函数不会被求值,但它可以生成对 __getattr__()的调用),并通过 dir()函数来匹配剩余部分。 在对表达式求值期间引发的任何异常都会被捕获、静默处理并返回 None