以自定义的方式读取数据
现在我们回头看看本节最开始遇到的那个问题。解决方法和水果例子完全相同,找到
模式,然后分组。
首先,看一下原始数据中典型的一行:
2014-02-01,09:20:29,Ken,James,Hey, how are you?
显然,每一行都具有相同的格式,也就是日期、时间、发送者、接收者、信息,并且
用逗号隔开。唯一特殊的是逗号可能出现在信息中,而我们不希望代码把信息中的逗号解
释为分隔符。
注意到,和前面的例子一样,正则表达式可以完美地达成这个目标。想要表达相同模
式下的一个或更多符号,只需在识别模式后面加上一个加号(+)。举个例子:"\d+"表示
一个字符串中包含一个或者更多“0”到“9”之间的数字字符。例如“1”、“23”、“456”
都匹配这个模式,而“word”不符合。在某些情况中,一个模式可能出现,也可能完全不
出现。那么我们需要将*放在识别模式符号后面,以标记这个特殊模式可能出现一次或更多
次,或者完全不出现,从而匹配更大范围的文本。
言归正传,我们需要在典型行中识别出一个足够一般的模式。我们想出如下分组模式:
(\d+-\d+-\d+),(\d+:\d+:\d+),(\w+),(\w+),\s*(.+)
现在,我们使用 readLines( )导入原始数据,就像在水果例子中所做的那样:
messages <- readLines("data/messages.txt")
然后,找出能够表达目标文本和信息的模式:
pattern <- "^(\\d+-\\d+-\\d+),(\\d+:\\d+:\\d+),(\\w+),(\\w+),\\s*(.+)$"
matches <- str_ _match(messages, pattern)
messages_df <- data.frame(matches[, -1])
colnames(messages_df) <- c("Date", "Time", "Sender", "Receiver", "Message")
这个模式看起来像一些密码。别担心,这就是正则表达式,而且如果你完成了前面的
例子,就会对它的含义有所理解。
正则表达式完美地完成了任务。message_df 文件的结构如下:
messages_df
## Date Time Sender Receiver Message
## 1 2014-02-01 09:20:25 James Ken Hey, Ken!
## 2 2014-02-01 09:20:29 Ken James Hey, how are you?
## 3 2014-02-01 09:20:41 James Ken I'm ok, what about you?
## 4 2014-02-01 09:21:03 Ken James I'm feeling excited!
## 5 2014-02-01 09:21:26 James Ken What happens?
我们使用的模式就像一把钥匙。任何正则表达式应用中最难的部分就是寻找这把钥匙。
一旦得到了它,就能够打开那道门,并从混乱的文本中尽可能多地提取需要的信息。一般
来说,寻找钥匙的难度很大程度上依赖于正例和反例的差异大小。如果差异足够明显,那
么少量符号就可以解决问题。如果差异很微小,又有许多特殊情况,如同现实世界中的大
多数问题,此时,需要更多的经验,努力思考并多次尝试,最终找到解决方法。
通过前面的例子,你应该已经领会了正则表达式的思想。其实,不需要深入地理解它是如
何工作的,但熟悉相关的函数,不论是内置函数,还是特定包内的函数,都是百利而无一害的。
如果想要深入学习,RegexOne (http://regexone.com/)是一个非常好的交互式基础学习场
所。想要学习更多特定案例和完整的识别符号,这个网页(http://www.regular-expressions.info/)
是一个很好的参考。想要寻找解决问题的好模式,可以浏览RegExr (http://www.regexr.com/)
在线交互式地测试不同的模式。