Excea VBA 正则表达式拆分字符串案例

今天记录一个关于字符串拆分的案例

将一个单元格中多行字符串,按内容拆分成多行多列!

先来看看源数据,总共3列,区域代码、项目代码和投保标的物信息,投保标的物信息中每一行都用空行间隔。任一行字符串,又分为4段,第1段是标的物,第2段是数量,第3段是单位,第4段是总投保金额。我们需要提取每一段中,“”后与空格前这之间的内容。最后的输出结果是这样的,区域代码、项目代码、标的物、数量、单位和总投保金额。一个标的物一行,项目有多个标的物,就输出多行。

尝试使用 VBAPower Query 两种解决方法。

打开Visual Basic,插入模块,写一个sub过程。

先将源数据装入数组;接着,再定义一个结果数据brr,最后的结果有多少行,暂时不知道,一维定义要足够大,这里给到 1 To 2000,结果有6列,二维定义 1 To 6。

处理字符串谁最强,当然是正则对象啦!声明并赋值正则对象,接着设置正则对象的Global属性为 True,匹配出所有的符合正则表达式的结果,如果是False只匹配第一个就会停止。Pattern属性,写上”=(:)(.?)(\\s). 表示0到多个的任意字符; ? 表示非贪婪匹配,尝试匹配尽可能少的字符; \\s 表示是不可见字符; () 总是打成一个组。这段字符的意思是以 : 开头,以空格结尾的中间0到多个的任意字符,结果分成为3组。

下面就是主要代码了。先遍历源数组,源数据的第1行是表头,不需要处理,所以从第2行开始遍历。要处理的是源数据的第3列,定义一个变量并赋值。

细心的朋友可能发现了要处理的字符串中间都有空白行,所以先用换行符来拆分单元格中的内容,拆分成每一行,方便后面处理。拆分字符串必须使用Split函数,分隔符用换行符(vbLf),使用变量trr接收拆分后的结果数组。

接着,对拆分后数组trr的元素进行逐一处理。依然还是遍历,遍历trr,先用正则对象的 Test 方法,测试能否匹配的到,如果匹配的到,返回 True,就进行累加计数,看看有多少行;brr的第1列,写入区域代码,第2列写入项目代码。接着用正则对象的Execute方法,对trr数组元素应用正则表达式,返回一个Match集合对象,用For Each遍历Match集合。

这里打个断点,打开立即窗口查看一下,发现每个Match下会有3个SubMatches对象,分别对应正则表达式的3个分组,下标是从0开始,要取的是下标为1的结果。

需要将Match集合对应的标的物、单位、数量和总投保金额转置成列,所以这里增加一个累加计数,前面已经有2列,也就是区域代码和项目代码,所以累加从3开始,累加变量初始值设置为2,再加1,就是从3开始。每一次遍历时,都会重置为变量初始值。

遍历结束,结果已经提取出来了,接下来就是把结果数组写入到结果表中。写入前,先清空结果表的已使用区域,清除原有内容。接着从结果表的A1单元格用Resize函数扩展1行6列,写入使用Array函数创建的表头数组;从结果表的A2单元格用Resize函数扩展2000行6列,写入结果数组brr。

回到结果表中,看看结果是不是已经出来了。

代码的功能已经实现了,还可以进一步优化,以提升运算速度,比如对正则对象和结果表使用with语句、代码结束后清空定义的对象释放内存、开始时关闭屏幕刷新,结束时记得一定要打开屏幕刷新。

整体代码比较简单,主要是正则表达式的理解。正则表达式很强大,经常处理字符串的朋友值得好好研究下。下一期,看看 Power Query 如何解决这个问题。

玩蛇(Python) – 字符串算法:正则表达式

一、正则表达式介绍

正则表达式(Regular Expressions,简称RE),正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个\”规则字符串\”,这个\”规则字符串\”用来表达对字符串的一种过滤逻辑。

Python的正则表达式会被编译成一系列字节码,然后由 C 语言编写的匹配引擎执行,以便达到最佳匹配效率。

正则表达式核心解析算法逻辑是确定性和非确定性有限自动机:

自动机:自动机就是一个有内部状态的机器。它有一个初始状态,而每当它接收到一个字符,它就根据字符和当前的内部状态,更新自己的内部状态(新状态与旧状态和输入字符之间的函数关系称为状态转移函数)。

确定性有限自动机(Deterministic Finite Automation, DFA): 是一个能实现状态转移的自动机。对于一个给定的属于该自动机的状态和一个属于该自动机字母表求和的字符,它都能根据事先给定的转移函数转移到下一个状态(这个状态可以是先前那个状态)。

非确定有限状态自动机(Non-Deterministic Finite Automation, NFA): 自动机下一个可能状态是唯一确定的。非确定有限自动机有时被称为有限类型的子移位(Sub-shift)。非确定有限状态自动机可推广为概率自动机,它为每个状态转移指派概率。

正则表达式在网络爬虫、数据分析中有着广泛使用,掌握正则表达式能够达到事半功倍的效果。

应用在如下场景中,也是高效简洁:

匹配和查找文本:使用正则表达式可以快速匹配和查找特定模式的文本,例如查找包含特定单词的句子、匹配邮箱、电话等;

数据清洗和处理:去除特定字符或标签、提取文本中的有效信息等;

表单验证:正则表达式可以用于验证用户输入的表单数据,验证邮箱地址是否合法等;

字符串替换:将文本中的某个模式替换为另一个字符串;

提取信息:提取特定的信息,例如提取网页中的链接,日志中的关键信息。

二、正则表达式字符详解

2.1 元字符列表:. ^ $ * + ? { } [ ] \\ | ( )

大多数字母和符号都会简单地匹配自身, 但该规则有例外。有些字符是特殊的 元字符(Meta Characters),并不匹配自身, 而是匹配一些非常规的内容,或者通过重复它们或改变它们的含义来影响正则的其他部分。

[]: 用于表示一个字符集合,字符可以单独列出,比如 [amk] 匹配 \’a\’, \’m\’, 或者 \’k\’;可以表示字符范围,通过用 \’-\’ 将两个字符连起来,例如:[0-5][0-9] 将匹配从 00 到 59 的两位数字;特殊字符在集合中会失去其特殊意义,比如 [(+*)] 只会匹配这几个字面字符之一 \'(\’, \’+\’, \’*\’, or \’)\’;如果集合首字符是 \’^\’ ,所有 不 在集合内的字符将会被匹配。

|:A|B, A 和 B 可以是任意正则表达式,创建一个正则表达式,匹配 A 或者 B,任意个正则表达式可以用 \’|\’ 连接。

():匹配括号内的任意正则表达式,并标识出组合的开始和结尾。

.(点号): 在默认模式下,匹配除换行符以外的任意字符。

^(插入符): 匹配字符串的开头。

$: 匹配字符串尾或者在字符串尾的换行符的前一个字符。

*: 对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。

+: 对它前面的正则式匹配1到任意次重复。

?: 对它前面的正则式匹配0到1次重复。

*?, +?, ??: \’*\’, \’+\’ 和 \’?\’ 数量限定符都是 贪婪的;它们会匹配尽可能多的文本。

*+, ++, ?+: 类似于 \’*\’, \’+\’ 和 \’?\’ 数量限定符,添加了 \’+\’ 的形式也将匹配尽可能多的次数。

{m}: 对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。比如, a{6} 将匹配6个 \’a\’ , 但是不能是5个。

{m,n}: 对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多。 比如,a{3,5} 将匹配 3 到 5个 \’a\’。

{m,n}?: 尝试匹配尽可能 少的重复次数。

{m,n}+: 尝试匹配尽可能多的重复而 不会建立任何反向追溯点。

\\(转移字符):转义特殊字符(\\)允许你匹配 \’*\’, \’?\’, 或者此类其他,或者表示一个特殊序列;特殊序列之后进行讨论。

2.2 特殊序列

\\d:匹配任何十进制数字,等价于字符类 [0-9] 。

\\D:匹配任何非数字字符,等价于字符类 [^0-9] 。

\\s:匹配任何空白字符,等价于字符类 [ \\t\\n\\r\\f\\v] 。

\\S:匹配任何非空白字符,等价于字符类 [^ \\t\\n\\r\\f\\v] 。

\\w:匹配任何字母与数字字符,等价于字符类 [a-zA-Z0-9_] 。

\\W:匹配任何非字母与数字字符,等价于字符类 [^a-zA-Z0-9_] 。

\\A: 只匹配字符串开始。

\\b: 匹配空字符串,但只在单词开始或结尾的位置。 一个单词被定义为一个单词字符的序列。

\\B: 匹配空字符串,但仅限于它 不在 单词的开头或结尾的情况。

2.3 运算符优先级

\\(转义符号):是用于转义其他特殊字符的转义符号。它具有最高的优先级。

()括号:圆括号用于创建子表达式,具有高于其他运算符的优先级。

*?+量词:量词指定前面的元素可以重复的次数。

字符类:字符类使用方括号 [] 表示,用于匹配括号内的任意字符。

^$断言:断言是用于检查字符串中特定位置的条件的元素。

连接:连接在没有其他运算符的情况下表示字符之间的简单连接。

|管道:管道符号 | 表示\”或\”关系,用于在多个模式之间选择一个。

三、Python正则表达式re(Regular Expressions)模块

3.1 re.match函数

尝试从字符串的起始位置匹配一个模式,如果匹配不成功返回none。匹配成功返回一个匹配的对象。

返回数据使⽤group⽅法来提取数据。group()用来提出分组截获的字符串,()用来分组,group() 同group(0)就是匹配正则表达式整体结果。

1) 语法

re.match(pattern, string, flags=0)

2) 参数

pattern:匹配的正则表达式

string: 要匹配的字符串

flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

  • re.I 忽略大小写
  • re.L 表示特殊字符集 \\w, \\W, \\b, \\B, \\s, \\S 依赖于当前环境
  • re.M 多行模式
  • re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
  • re.U 表示特殊字符集 \\w, \\W, \\b, \\B, \\d, \\D, \\s, \\S 依赖于 Unicode 字符属性数据库
  • re.X 为了增加可读性,忽略空格和 # 后面的注释

3) 实例

3.2 re.search函数

re.search 扫描整个字符串并返回第一个成功的匹配。

1) 语法

re.search(pattern, string, flags=0)

2) 参数

pattern: 匹配的正则表达式

string: 要匹配的字符串。

flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

3) 实例

3.3 re.split函数

split方法按照能够匹配的子串将字符串分割后返回列表。

1) 语法

re.split(pattern, string[, maxsplit=0, flags=0])

2) 参数

pattern: 匹配的正则表达式

string: 要匹配的字符串。

maxsplit: 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。

flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等。

3) 实例

源码下载:

https://github.com/ShanGouXueHui/PythonAlgorithm

##山狗学会 License Start##

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。