Rpy|字符串处理|总结与进阶

浏览: 1340

本专题总结

本专题一共四篇文章,这是第四篇,在这里对前三篇文章进行总结,再进行进一步的分析,最后说一些更高级的字符串处理。

  • 字符串处理综述篇:主要讲述本专题字符串处理学习的基本思路,列出学习框架,给出R与python字符串处理的各种资源。同时给出了一个在学习上普世的方法论,虽然放在字符串处理这个专题下面,但是我认为相比于字符串处理,这个方法论是我更想和大家分享的内容,在以后的专题中,我们还会经常使用这个方法论来学习。
  • 字符串处理R篇:主要分为两个部分,一个是使用基础函数,一个是使用stringr包。
  • 字符串处理python篇:主要分为两个部分,一个是字符串方法和re库,另一个是pandas库。

后两篇文章根据综述中讲述的学习框架,填充知识点,使知识更加系统完整。四种方法都附有实践练习,让读者更清楚地了解其用途。

各种方法对比分析

虽然知识按照框架填充好了,但是只有将这四种方法放在一起对比一番,才能有更深的理解。我最后用每一种方法处理相同的问题,正是要对比其中的差异。

这里还是贴上这张字符串处理需求的图


  • 在R语言篇,我们讲述了stringr包几乎全部重写了基础的函数,而且使用简单,运行快速,基础函数方法可以完全被替代掉。

  • stringr包和python字符串方法和re库的比较上,前者较后者多了向量化操作,避免了循环,这是一个优势。但是分组提取没有后者那么灵活,从提取电影名上就可以看得出来。

  • pandas库将python的字符串方法全部向量化,同时支持正则表达式和re库中的函数功能,可谓集stringr和字符串方法之大成。

  • 后三者虽然有些许的差异,但是差别微乎其微,完全可以独当一面。

虽然pandas库功能最强,但是它是用来做数据分析的,很少有听说在爬虫等地方还专门用这个库来提取字符串,因为向量化并不是不可替代的。所以下面我们拿re库来代表python,与R做一个比较。

相比之下,R语言的最大特点就是支持向量化操作,同时擅长在向量里面处理。所以读取文件中的长字符串时,常常喜欢分行读取,或者读取整个字符串之后按换行符\n进行拆分,每一行作为字符串的一个元素,再对这个向量进行操作。

而python提取、分组功能足够强大,常常可以直接处理整个大的字符串,比如爬取网页源代码之后,可以直接根据标签选取所需内容。

暂时想到这些,以后想到还会补充。

字符串的高级使用方法

在接触字符串处理过程中,会遇到各种各样意想不到的难题,这就需要我们更深入地研究。正则表达式作为一个非常强大的工具,如果能够熟练掌握,就能解决许多平常方法难以解决的问题。网上大多数教程都只是初级的使用,比较深的内容即使讲述了原理,初学者还是不知道能用来哪个地方。就比如正则表达式更深的东西,如果不是真正遇到那种问题,根本想不出这些复杂的方法有什么用。

原理部分之前列的资源里都有,这里我会举几个高级方法使用的例子。

下面处理几个相对比较有难度的问题,主要基于正则表达式,使用stringr包完成

1.一个注意事项:使用|实现”或”的功能,但是这里要注意,这个”或”两侧的东西不是完全等价的。在整个字符串中先按照|前面的找一遍匹配好了,再按照后面的找有没有漏的。而如果放在[]中实现或的功能则二者同等地位。我们来看下面一个例子

a <- "aaajafdkj"
str_extract_all(a,"a\\w*?j|a\\w*?a")
# "aaaj" "afdkj"
str_extract_all(a,"a\\w*?[aj]")
# "aa" "aj" "afdkj"

# 下面是不加?的贪婪模式的情况
str_extract_all(a,"a\\w*j|a\\w*a")
# "aaajafdkj"

其中\w*是指0个或多个字母,加一个?表示非贪婪模式,如果是默认的贪婪模式,上来就会把整个的”aaajafdkj”全匹配下来,因为整个的也满足开头a中间字母最后f的格式,贪婪模式会一次就把最长的匹配出来。

2.零宽断言:之前讲R语言字符串处理(链接)的例子中,我们使用stringr包提取电影名称方法比较麻烦,这里使用较高级的正则表达式——零宽断言一步提取。

library(stringr)
b <- '<span class="title">肖申克的救赎</span>
<span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
<span class="other">&nbsp;/&nbsp;月黑高飞(港) / 刺激1995(台)</span>

<span class="title">这个杀手不太冷</span>
<span class="title">&nbsp;/&nbsp;Léon</span>
<span class="other">&nbsp;/&nbsp;杀手莱昂 / 终极追杀令(台)</span>

<span class="title">霸王别姬</span>
<span class="other">&nbsp;/&nbsp;再见,我的妾 / Farewell My Concubine</span>'

str_extract_all(b,'(?<=<span class="title">)\\w+(?=</span>)')
# "肖申克的救赎" "这个杀手不太冷" "霸王别姬"
# python中的使用如下
# re.findall('(?<=<span class="title">)\w+(?=</span>)',b)

这里解释一下,两个括号是零宽断言的两种不同形式,零宽断言可以实现匹配但是不作为的功能。不作为可以是,括号里的内容,在使用extract时不被提取、split时不按照它拆分、replace时不被替换。

?<= 代表匹配到的内容前面是<span class="title">, ?=表示匹配到的内容后面是

,这两个位置可以换成其他东西。

这里匹配不作为表示虽然匹配找到了 <span class="title">霸王别姬</span> 这整条,但是不对括号中的内容执行提取的功能,而是对匹配到的其他位置执行,这里就是两个括号中间的\w+对应的电影名被提取出来了。

下面我们还有零宽断言的例子。

3.找到字符串中所有ab,从ab中间split拆开成为多个字符串,如(“abcdabc”)→(“a” “bcda” “bc”)。使用两种方法

  • 用aabb替代ab,然后split以ab为分隔符

    a <- "abcdabc"
    a1 <- str_replace_all(a,"ab","aabb")
    str_split(a1,"ab") # "a" "bcda" "bc"

  • 直接用正则表达式中的零宽断言实现

    str_split(a,"(?<=a)(?=b)") # "a" "bcda" "bc"

    此处?<= 代表匹配到的内容前面是a,?=表示匹配到的内容后面是b。而括号中间没有内容,则正好是匹配到了ab,按照中间的空白拆分,完美实现我们想要的功能。

4.函数常常可以全部替换或者只替换第一个,但是如果只要替换第三个匹配怎么办?提取一般也涉及到提取全部或者第一个,但是想要第三个可以先提取全部,再从里面提取,不过替换就不行。

思路:匹配的时候就把该位置前面整块都匹配下来,替换时末尾更改,其他的原封不动。我们使用正则表达式中的引用组号功能,给提取的某一部分编号或命名,替换时直接引用编号或名称,将该部分填回去。

s <- "cat goose  mouse cat horse pig cat cow"
# 使用默认编号
str_replace(s,'((.*?cat.*?){2})cat', '\\1CAT')
# "cat goose mouse cat horse pig CAT cow"

要想替换第几个,只要把{2}中的数字改一下就好了。

其中.*?代表任意字符(多少个无所谓),这个括号中的内容就代表一个带这1个cat的字符串。{2}代表前面这个的字符串有2个。这两个带有cat的字符串和最后那个cat共同形成匹配的pattern,这个?是非贪婪模式的意思,这样一个括号中才不会匹配到两个cat。

匹配到之后,要保留前面两个带cat的字符串,替换掉最后一个。括号代表分组,最后一个cat前面那个括号代表那里面的内容是一组,这些正好是我们想要保持原封不动的。组会自动编号,从1开始,使用我们后面直接用\1引用这个第一组,加上我们想要替换后面cat的内容,实现了只对第三个cat替换的目的。

5.提取一句话中重复的字母——引用分组。这里使用自定义名字的方法

str_extract("saafafdf","(?<char>\\w)\\k<char>") # "aa"

暂时有这些例子,以后我如果遇到其他有趣的例子会继续往这里补充。

专栏信息

专栏主页:Data Analysis
专栏目录:目录

文末彩蛋

这里讲一讲代码规范,规范的代码可以增加可读性,不仅方便别人理解你的代码,同时也方便了自己日后看自己写的代码。良好的编程习惯体现一个人的素养,所以应该今早养成规范代码书写的习惯。

代码规范包括空格的添加、变量的命名、注释的添加等内容,这些早已有人总结好,不再赘述,下面只贴上学习链接。

Google's R Style Guide

advance R

推荐 0
本文由 dwzb 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

1 个评论

点赞

要回复文章请先登录注册