Skip to main content

CP04字符串识别与信息提取

阅读:-


由于现实世界用于编制报表的数据源非常的多,我们常常需要从字符串中提取特定的信息结构,用于生产需要的信息结构,所以对于字符串的处理,是非常重要的一种报表制作基础,今天我们就重点理解一下,相关的技术要点吧。

4 字符串识别与信息提取

4.1 用例故事

在日常报表分析的时候,我们常常需要对报表的信息结构加以筛选和提取,形成新的信息结构。

在 5G 时代,物联网应用比较流行,一个物联网的网络中,一般是有多个工作站(work-station) 组成的, 每个 work-station 在定期上报自己的配置信息,其中有一个非常重要的 DN 字段,用于标示这个 work-station 的身份信息,和我们个人的身份证很类似。

关于 DN 大概的结构说明如下:

ERI-CMHB-WH,SubNetwork=1,ManagedElement=21111,GNBCUCPFunction=6111111,GNODEBPARAM=21111

每个 work-station 的配置信息都包含一系列的信息结构,并以字符串的形式拼接在一起,基本上采用一种 key-value 的格式,以上面的信息结构来看,大致的结构见下表:

表 5-1 DN中包含的key-value结构

keyvalue
SubNetwork1
ManagedElement21111
GNBCUCPFunction6111111
GNODEBPARAM21111

为了方便应用相关的数据,我们需要从一长串的字符串中,识别出关注的key,并从其中提取对应的value的数值,提取数值以后,就可以拼接出我们需要的work-staiton 的 标识信息。

4.1.1 用例描述

  1. 用户输入期待处理的文件路径,输出结果文件的,相关的信息结构
[输入文件绝对路径,输出文件绝对路径];

举例如下:[D:\PAE\workstation.csv, D:\PAE\workstation-id.csv]
  1. 程序读取 workstation.csv 文件,转换为内存中的中间流,成为一个 Data set 的格式。

  2. 程序根据入参中“输出文件绝对路径”,创建一个输出结果 csv 文件的句柄。

  3. 应用程序对 Data set 的表头进行扩展,增加一列,名字为 workstation-id

  4. 应用程序查索 DN 列数据

  5. 在 DN 列中的行数据进行逐行遍历处理。

6.1 应用程序识别出第一行数据中 DN 列的字符串,对字符串进行扫描,找到 key=GNBCUCPFunction,识别出其中的 value。

6.2 对 GNBCUCPFunction 的值与 460-00 进行拼接,形成一个新的字符串格式为 460-00-value(key= GNBCUCPFunction)。

6.3 将新生成的字符串 460-00-value(key= GNBCUCPFunction)赋值到同一行的新字段 workstation-id

6.4 一行处理完毕以后,顺序处理后续行的数据。

  1. 全部数据处理完毕以后,实现对 workstation-id 列的赋值。

  2. 应用程序将内存中的 data set 写入输出结果 csv 文件的句柄, 相关文件决对路径来自输入数据。

举例:D:\PAE\workstation-id.csv

  1. 应用程序返回程序执行响应 [ 执行结果,输出结果文件信息]

其中执行结果:0 成功 1 失败

输出结果文件信息:提供输出结果文件的决对路径,举例如下:

D:\PAE\ workstation-id.csv

疑问: 实际的执行过程中,结果文件的句柄在那个环节打开, 什么时候关闭,建议思考一下,方便用例阐述的更加清晰。

4.1.2 输入数据准备

1587286954776

相关的数据格式为:

1587286974293

4.1.3 IPO 分析

4.1.3.1 输入数据分析(I)

用户输入期待扫描的文件路径和文件类型,相关的信息结构

[ 输入文件绝对路径,输出文件绝对路径]

举例如下:[D:\PAE\workstation.csv, D:\PAE\workstation-id.csv]

4.1.3.2 处理过程(P)

下面以一行数据的处理过程,为例说明相关的主要处理过程:

假设待处理的 DN 列 中对应的字符串是:

ERI-CMHB-WH,SubNetwork=1,ManagedElement=21111,GNBCUCPFunction=6111111,GNODEBPARAM=21111

1.首先对字符串按照“,”进行拆分,获得 5 个元素

[ERI-CMHB-WH,SubNetwork=1,ManagedElement=21111,GNBCUCPFunction=6111111,GNODEBPARAM=21111]

2.对字符串进行匹配,过滤出待处理的元素 GNBCUCPFunction=6111111

3.针对元素 GNBCUCPFunction=6111111 按照“=”进行拆分,获得 2 个元素[GNBCUCPFunction, 6111111]

4.将第二个元素 6111111,和字符串 460-00 进行拼接,形成一个新的字符串格式为 460-00-value(key= GNBCUCPFunction)

5.将新合成的字符串 460-00-value(key= GNBCUCPFunction),赋值给本行中,新增加的字段 workstation-id。

相关的意涵就是 key= workstation-id, value=460-00-value(key= GNBCUCPFunction);

4.1.3.3 输出数据(O)

应用程序返回程序执行响应 [ 执行结果,输出结果文件信息]

其中执行结果:0 成功 1 失败

输出结果文件信息:提供输出结果文件的决对路径,举例如下:

D:\PAE\ workstation-id.csv

4.1.4 用例约束

  1. 请使用 os 组件进行读写

  2. 请使用 str 进行数据处理

  3. 请使用 list 进行处理

4.1.5 扩展用例

设计约束: 请使用 CSV 组件进行文件读写.

4.2 设计方案简介

4.2.1 Csv 方案

4.2.1.1 设计要点

字符串拆分

4.2.1.2 调用关系

1587287124296

4.2.1.3 流转换

  1. csv_rows = csv_reader(filename)

print(csv_rows)

1587287162829

  1. 头部即为 csv_rows[0]

1587287190240

  1. for row in csv_rows[1:]:得出后续所有行

1587287213450

  1. 应用字典生成式:

1587287234640

  1. row[6]= “460-00-”+Dn_data[“GNBCUCPFunction”]

根据 dict-hash 重新给 list 赋值

1587287270891

6、将 list 写入本地

1587287296388

4.2.2 Os 方案

4.2.2.1 调用关系

1587287341713

4.2.2.2 流转换

1、print(header_txt)

打印头部信息结构

1587287380408

2、f_txt

1587287397722

3、遍历 f-txt

for i in f_txt:

1587287422045

4、 应用 dict

Dn_data = {item.split('=')[0]: item.split('=')[1]

        for item in i.split(",") if item.find('=') > 0}

1587287453165

5、 取字典 hash 改变 list

workstation_id = "460-00-" + Dn_data["GNBCUCPFunction"]

1587287488091

6、 写入 csv 文件

1587287516704

4.3 CSV 设计方案详解

4.3.1 领域对象模型

![1587287546555](./1587287546555.png)

图 3-4 基于 CSV 方案的合并

从上图可见,相关的方案中核心的函数为 merge(filelist,dist)

相关核心的领域对象说明如下

1.写文件句柄: 在这个方案中,有两个写文件句柄,其中 distfile 是一个 OS 级别的句柄,而 csvwriter 是进一步基于 CSV 组件进行封装的 APP 级别的句柄,经过封装以后,写写操作很方便。

2.CSV_rows:这是一个列表,他是将 CSV 文件转换为一个列表,其中包含的元素的数量=表头+数据行数。

3.header[] 这也是一个列表,负责记录表头的信息结构,并方便做一些合规性的判断。

从上图可见,基本的函数调用关系和多 CSV 合并这一题非常类似。

4.3.1.1 字符串转换相关用例回顾

接下来我们看看本题中和字符串相关的内容:

下面以一行数据的处理过程,为例说明相关的主要处理过程:

假设待处理的 DN 列 中对应的字符串是:

ERI-CMHB-WH,SubNetwork=1,ManagedElement=21111,GNBCUCPFunction=6111111,GNODEBPARAM=21111

1,首先对字符串按照“,”进行拆分,获得 5 个元素

[ERI-CMHB-WH,SubNetwork=1,ManagedElement=21111,GNBCUCPFunction=6111111,GNODEBPARAM=21111]

2, 对字符串进行匹配,过滤出待处理的元素 GNBCUCPFunction=6111111

3、针对元素 GNBCUCPFunction=6111111 按照“=”进行拆分,获得 2 个元素[GNBCUCPFunction, 6111111]

4、将第二个元素 6111111,和字符串 460-00 进行拼接,形成一个新的字符串格式为 460-00-value(key= GNBCUCPFunction)

5、将新合成的字符串 460-00-value(key= GNBCUCPFunction),赋值给本行中,新增加的字段 workstation-id。

相关的意涵就是 key= workstation-id, value=460-00-value(key= GNBCUCPFunction);

4.3.1.2 字符串拆分的模型

1587287599566

图 4-5 字符串拆分模型

从上图可见, 本案例中,大量使用了字符串的操作,

下面将简要说明一下,相关的过程。

1.将 CSV 文件转换为一个 list 以后,分为两个部分,其中

1.1 CSV_rows[0], 代表了相关的 CSV 的表头信息。

1.2 csv_rows[1:]: 后续的元素,是 CSV 的数据,

  1. 针对 csv_rows[1:]中的一行数据,也是一个列表,定位到其中的第三个元素,也就是 DN 字段所以对于的信息结构,是一个字符串。

    2.1 字符串的结构为:

ERI-CMHB-WH,SubNetwork=1,ManagedElement=21111,GNBCUCPFunction=6111111,GNODEBPARAM=21111

2.2 调用字符串的 split() 的方法,将字符串转换为一个 list

形态为:

[ERI-CMHB-WH,SubNetwork=1,ManagedElement=21111,GNBCUCPFunction=6111111,GNODEBPARAM=21111]

3.针对列表中的元素,我们称为 item,进行遍历,如果包含了=,则进行处理。

 3.1 将包含‘=’的item 进行按照‘=’进行拆分, 形成一个列表, 这个列表中,第一个元素为key,第二个元素为value。

 3.2 将第一个元素为key,第二个元素为value赋值给一个dict

以上是主要的处理过程。

4.3.1.3 字符串的拆分方法

在本案例中大量应用了字符串的拆分方法,相关的返回值是一个 list。 参考一下的说明。

1587287651792

4.3.1.4 字典对象生成式

1587287671128

 图 4-6 DN生成方式

从上图可见,本题目中有一个核心的处理,是将每一行数据的中 DN 字段,是一个字符串,转换为 1 个字典。

这里使用了一个字典生成方式的操作。

Dn_data = {item.split('=')[0]: item.split('=')[1] for item in row[2].split(",") if item.find('=') > 0}

这样就可以方便的生成相关的字典结构。

在这个案例中,我们展现了如何把一个字符串,转换为一个字典对象。

4.3.2 关键技能点

1587287695065

4.3.3 字符串转换为字典

4.3.3.1 应用目的

根据实际应用场景进行选择,此处需要根据 id 选择对应值,适用于 dict

4.3.3.2 语法说明

{I for I in 可迭代对象}

4.3.3.3 Case 举例

待处理数据结构如下:

测试一,测试二,“HW-CMHB-WH,SubNetwork=1,ManagedElement=29388,GNBCUCPFunction=6292914,GNODEBPARAM=29388”,测试三,2019-12-30T00:49:38,UTC+8,

{item.split('=')[0]: item.split('=')[1]
          for item in i.split(",") if item.find('=') > 0}

4.3.3.4 应用注意点

因考虑实际场景进行选择

4.3.4 string 对象主要方法

4.3.4.1 应用目的

操作 str 提取关键信息

4.3.4.2 语法说明

1587288091899

4.3.4.3 Case 举例

字符串内置函数详情表如下:

方法描述
string.capitalize()把字符串的第一个字符大写
string.center(width)返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
string.count(str, beg=0, end=len(string))返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
string.decode(encoding=‘UTF-8’, errors=‘strict’)以 encoding 指定的编码格式解码 string,如果出错默认报一个 ValueError 的 异 常 , 除非 errors 指 定 的 是 ‘ignore’ 或 者’replace’
string.encode(encoding=‘UTF-8’, errors=‘strict’)以 encoding 指定的编码格式编码 string,如果出错默认报一个 ValueError 的异常,除非 errors 指定的是’ignore’或者’replace’
string.endswith(obj, beg=0, end=len(string))检查字符串是否以 obj 结束,如果 beg 或者 end 指定则检查指定的范围内是否以 obj 结束,如果是,返回 True,否则返回 False.
string.expandtabs(tabsize=8)把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8。
string.find(str, beg=0, end=len(string))检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1
string.format()格式化字符串
string.index(str, beg=0, end=len(string))跟 find()方法一样,只不过如果 str 不在 string 中会报一个异常.
string.isalnum()如果 string 至少有一个字符并且所有字符都是字母或数字则返 回 True,否则返回 False
string.isalpha()如果 string 至少有一个字符并且所有字符都是字母则返回 True, 否则返回 False
string.isdecimal()如果 string 只包含十进制数字则返回 True 否则返回 False.
string.isdigit()如果 string 只包含数字则返回 True 否则返回 False.
string.islower()如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
string.isnumeric()如果 string 中只包含数字字符,则返回 True,否则返回 False
string.isspace()如果 string 中只包含空格,则返回 True,否则返回 False.
string.istitle()如果 string 是标题化的(见 title())则返回 True,否则返回 False
string.isupper()如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
string.join(seq)以 string 作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
string.ljust(width)返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
string.lower()转换 string 中所有大写字符为小写.
string.lstrip()截掉 string 左边的空格
string.maketrans(intab, outtab])maketrans() 方法用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
max(str)返回字符串 str 中最大的字母。
min(str)返回字符串 str 中最小的字母。
string.partition(str)有点像 find()和 split()的结合体,从 str 出现的第一个位置起,把 字 符 串 string 分 成 一 个 3 元 素 的 元 组 (string_pre_str,str,string_post_str),如果 string 中不包含 str 则 string_pre_str == string.
string.replace(str1, str2, num=string.count(str1))把 string 中的 str1 替换成 str2,如果 num 指定,则替换不超过 num 次.
string.rfind(str, beg=0,end=len(string) )类似于 find()函数,不过是从右边开始查找.
string.rindex( str, beg=0,end=len(string))类似于 index(),不过是从右边开始.
string.rjust(width)返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
string.rpartition(str)类似于 partition()函数,不过是从右边开始查找
string.rstrip()删除 string 字符串末尾的空格.
string.split(str="", num=string.count(str))以 str 为分隔符切片 string,如果 num 有指定值,则仅分隔 num+ 个子字符串
[string.splitlines(keepends])按照行(‘\r’, ‘\r\n’, \n’)分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
string.startswith(obj, beg=0,end=len(string))检查字符串是否是以 obj 开头,是则返回 True,否则返回 False。如果 beg 和 end 指定值,则在指定范围内检查.
string.strip([obj])在 string 上执行 lstrip()和 rstrip()
string.swapcase()翻转 string 中的大小写
string.title()返回”标题化”的 string,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())
string.translate(str, del="")根据 str 给出的表(包含 256 个字符)转换 string 的字符, 要过滤掉的字符放到 del 参数中
string.upper()转换 string 中的小写字母为大写
string.zfill(width)返回长度为 width 的字符串,原字符串 string 右对齐,前面填充 0

4.3.4.4 应用注意点

根据实际应用场景进行选择

4.4 OS 方案详解

4.4.1 领域对象模型

1587288210988

图 4-7 基于 OS 方案的对象模型

从上图可见,这是一个基础的 OS 方案,总体书写比较简单,但是封装性不是很好。

4.4.2 关键技能点

OS 文件读取/合并1,如何将 list 写入 csvlist 转字符串

4.4.3 如何将 list 写入 csv

4.4.3.1 应用目的

将 list 写入 csv 文件

4.4.3.2 语法说明

out.write(",".join(content))

4.4.3.3 Case 举例

1587288308257

4.4.3.4 应用注意点

根据实际场景,进行应用

4.5 总结

本章重点学习了三个内容

  1. 如何对字符串进行 split() 操作,以及 string 对象的一些基础操作。

  2. 如何将字符串转换为字典。

    3.如何将 list 转换为字符串,输出到 CSV 文件。

另外本案例中,也有大量的文件对象的读写操作处理。

分享到微博
Starter
MicroServ
Tutorials
Report
Blog