• R 语言学习笔记
  • 欢迎
  • 1 前言
    • 1.1 语言抉择
    • 1.2 数据科学
    • 1.3 写作环境
  • I 数据整理
  • 介绍
  • 2 数据结构
    • 2.1 类型
    • 2.2 字符
    • 2.3 向量
    • 2.4 矩阵
    • 2.5 数组
    • 2.6 表达式
    • 2.7 列表
    • 2.8 日期
    • 2.9 空值
  • 3 数据搬运
    • 3.1 导入数据
      • 3.1.1 scan
      • 3.1.2 read.table
      • 3.1.3 readLines
      • 3.1.4 readRDS
    • 3.2 其它数据格式
    • 3.3 导入大数据集
    • 3.4 从数据库导入
      • 3.4.1 PostgreSQL
      • 3.4.2 MySQL
      • 3.4.3 Spark
    • 3.5 批量导入数据
    • 3.6 批量导出数据
    • 3.7 导出数据
      • 3.7.1 导出运行结果
      • 3.7.2 导出数据对象
    • 3.8 Spark 与 R 语言
      • 3.8.1 sparklyr
      • 3.8.2 SparkR
    • 3.9 数据库与 R 语言
    • 3.10 批量读取 csv 文件
    • 3.11 批量导出 xlsx 文件
    • 3.12 运行环境
  • 4 字符串操作
    • 4.1 字符数统计
    • 4.2 字符串翻译
    • 4.3 字符串连接
    • 4.4 字符串拆分
    • 4.5 字符串匹配
    • 4.6 字符串查询
    • 4.7 字符串替换
    • 4.8 字符串提取
    • 4.9 命名捕捉
    • 4.10 精确匹配
    • 4.11 模糊匹配
    • 4.12 高级的替换
    • 4.13 高级的提取
    • 4.14 其它操作
      • 4.14.1 strwrap
      • 4.14.2 strtrim
      • 4.14.3 strrep
      • 4.14.4 trimws
      • 4.14.5 tolower
    • 4.15 字符串加密
    • 4.16 处理性能
    • 4.17 网络爬虫
    • 4.18 文本挖掘
    • 4.19 运行环境
  • 5 正则表达式
    • 5.1 字符常量
    • 5.2 软件环境
    • 5.3 基本概念
    • 5.4 字符串匹配
    • 5.5 级联表达式
    • 5.6 反向引用
    • 5.7 命名捕捉
    • 5.8 表达式注释
  • 6 数据操作
    • 6.1 查看数据
    • 6.2 提取子集
    • 6.3 数据重塑
    • 6.4 数据转换
    • 6.5 按列排序
    • 6.6 数据拆分
    • 6.7 数据合并
    • 6.8 数据去重
    • 6.9 数据缺失
    • 6.10 数据聚合
    • 6.11 表格统计
    • 6.12 索引访问
    • 6.13 多维数组
    • 6.14 其它操作
      • 6.14.1 列表属性
      • 6.14.2 堆叠向量
      • 6.14.3 属性转化
      • 6.14.4 绑定环境
      • 6.14.5 数据环境
    • 6.15 apply 族
    • 6.16 with 选项
    • 6.17 分组聚合
    • 6.18 合并操作
    • 6.19 长宽转换
    • 6.20 对符合条件的列操作
    • 6.21 CASE WHEN 和 fcase
    • 6.22 数据操作实战
    • 6.23 高频数据操作
      • 6.23.1 循环合并
      • 6.23.2 分组计数
      • 6.23.3 分组抽样
      • 6.23.4 分组排序
  • 7 高级数据操作
    • 7.1 基础介绍
      • 7.1.1 过滤
      • 7.1.2 变换
      • 7.1.3 聚合
      • 7.1.4 命名
      • 7.1.5 排序
      • 7.1.6 变形
      • 7.1.7 分组
      • 7.1.8 合并
    • 7.2 高频操作
      • 7.2.1 选择多列
      • 7.2.2 过滤多行
      • 7.2.3 去重多行
      • 7.2.4 合并操作
      • 7.2.5 新添多列
      • 7.2.6 删除多列
      • 7.2.7 筛选多列
      • 7.2.8 修改多列类型
      • 7.2.9 取每组第一行
      • 7.2.10 计算环比同比
      • 7.2.11 合并多个数据框
      • 7.2.12 分组聚合多个指标
      • 7.2.13 重命名多个列
      • 7.2.14 对多个列依次排序
      • 7.2.15 重排多个列的位置
      • 7.2.16 整理回归结果
      • 7.2.17 := 和 .()
      • 7.2.18 去掉含有缺失值的记录
      • 7.2.19 集合操作
      • 7.2.20 对数值向量按既定分组计数
      • 7.2.21 分组排序
      • 7.2.22 分组获取 Top 值
      • 7.2.23 分组抽样
      • 7.2.24 分组计算分位数
      • 7.2.25 计算日粒度的 DoD/WoW/MoM/YoY
    • 7.3 运行环境
  • 8 并行化操作
    • 8.1 apply
    • 8.2 MapReduce
    • 8.3 parallel
    • 8.4 Rmpi
    • 8.5 gpuR
    • 8.6 运行环境
  • 9 净土化操作
    • 9.1 常用操作
      • 9.1.1 查看
      • 9.1.2 筛选
      • 9.1.3 排序
      • 9.1.4 聚合
      • 9.1.5 合并
      • 9.1.6 变换
      • 9.1.7 去重
    • 9.2 高频问题
      • 9.2.1 初始化数据框
      • 9.2.2 移除缺失记录
      • 9.2.3 数据类型转化
      • 9.2.4 跨列分组求和
    • 9.3 管道操作
  • II 统计图形
  • 介绍
  • 10 图形基础
    • 10.1 绘图基本要素
      • 10.1.1 点线
      • 10.1.2 区域
      • 10.1.3 参考线
      • 10.1.4 坐标轴
      • 10.1.5 刻度线
      • 10.1.6 标题
      • 10.1.7 注释
      • 10.1.8 图例
      • 10.1.9 边空
      • 10.1.10 图层
      • 10.1.11 布局
      • 10.1.12 组合
      • 10.1.13 分屏
      • 10.1.14 交互
    • 10.2 基础统计图形
      • 10.2.1 条形图
      • 10.2.2 直方图
      • 10.2.3 密度图
      • 10.2.4 经验图
      • 10.2.5 QQ 图
      • 10.2.6 时序图
      • 10.2.7 饼图
      • 10.2.8 茎叶图
      • 10.2.9 散点图
      • 10.2.10 抖动图
      • 10.2.11 箱线图
      • 10.2.12 残差图
      • 10.2.13 提琴图
      • 10.2.14 轮廓图
      • 10.2.15 折线图
      • 10.2.16 函数图
      • 10.2.17 马赛克图
      • 10.2.18 点图
      • 10.2.19 矩阵图
      • 10.2.20 雷达图
      • 10.2.21 玫瑰图
      • 10.2.22 透视图
    • 10.3 栅格统计图形
      • 10.3.1 时序图
      • 10.3.2 水平图
      • 10.3.3 折线图
      • 10.3.4 高级设置
      • 10.3.5 柱形图
      • 10.3.6 Rootograms
      • 10.3.7 透视图
  • 11 可视化之配色
    • 11.1 调色板
    • 11.2 颜色模式
      • 11.2.1 RGB
      • 11.2.2 HSL
      • 11.2.3 HSV
      • 11.2.4 HCL
      • 11.2.5 CMYK
    • 11.3 LaTeX 配色
    • 11.4 ggplot2 配色
  • 12 可视化之图库
    • 12.1 饼图
    • 12.2 地图
    • 12.3 热图
    • 12.4 散点图
    • 12.5 条形图
    • 12.6 直方图
    • 12.7 箱线图
    • 12.8 函数图
    • 12.9 密度图
    • 12.10 提琴图
    • 12.11 抖动图
    • 12.12 蜂群图
    • 12.13 玫瑰图
    • 12.14 瓦片图
    • 12.15 日历图
    • 12.16 岭线图
    • 12.17 椭圆图
    • 12.18 Q-Q 图
    • 12.19 包络图
    • 12.20 拟合图
    • 12.21 地形图
    • 12.22 树状图
    • 12.23 留存图
    • 12.24 瀑布图
    • 12.25 水流图
    • 12.26 时间线
    • 12.27 三元图
    • 12.28 向量场图
    • 12.29 四象限图
    • 12.30 龙卷风图
    • 12.31 聚类图
    • 12.32 主成分图
    • 12.33 组合图
    • 12.34 动态图
  • 13 交互图形
    • 13.1 散点图
    • 13.2 条形图
    • 13.3 折线图
    • 13.4 双轴图
    • 13.5 气泡图
    • 13.6 曲线图
    • 13.7 堆积图
    • 13.8 热力图
    • 13.9 地图上的散点图
    • 13.10 拟合图
    • 13.11 轨迹图
    • 13.12 甘特图
    • 13.13 帕雷托图
    • 13.14 时间线
    • 13.15 漏斗图
    • 13.16 雷达图
    • 13.17 瀑布图
    • 13.18 树状图
    • 13.19 旭日图
    • 13.20 调色板
    • 13.21 地图 II
    • 13.22 动画
    • 13.23 网络图
      • 13.23.1 networkD3
      • 13.23.2 visNetwork
      • 13.23.3 r2d3
    • 13.24 运行环境
  • III 统计计算
  • 介绍
  • 14 数值优化
    • 14.1 线性规划
    • 14.2 整数规划
      • 14.2.1 一般整数规划
      • 14.2.2 0-1 整数规划
      • 14.2.3 混合整数规划
    • 14.3 二次规划
      • 14.3.1 凸二次规划
      • 14.3.2 半正定二次优化
    • 14.4 非线性规划
      • 14.4.1 一元非线性优化
      • 14.4.2 多元非线性无约束优化
      • 14.4.3 多元非线性约束优化
  • 15 微分方程
    • 15.1 常微分方程
    • 15.2 偏微分方程
    • 15.3 延迟微分方程
    • 15.4 随机微分方程
  • 附录
  • A 命令行操作
    • A.1 查看文件
    • A.2 创建文件夹
    • A.3 移动文件
    • A.4 查看文件大小
    • A.5 终端模拟器
    • A.6 压缩和解压缩
    • A.7 从仓库安装 R
      • A.7.1 Ubuntu
      • A.7.2 CentOS
    • A.8 源码安装
      • A.8.1 Ubuntu
      • A.8.2 CentOS
    • A.9 忍者安装
    • A.10 配置
      • A.10.1 初始会话 .Rprofile
      • A.10.2 环境变量 .Renviron
      • A.10.3 编译选项 Makevars
    • A.11 命令行参数
    • A.12 从源码安装 R
    • A.13 安装软件
    • A.14 安装 R 包
    • A.15 软件包管理器
      • A.15.1 dnf
      • A.15.2 apt
  • 参考文献
  • Published with Github Pages

R 语言学习笔记

4.6 字符串查询

grep(pattern, x,
  ignore.case = FALSE, perl = FALSE, value = FALSE,
  fixed = FALSE, useBytes = FALSE, invert = FALSE
)
grepl(pattern, x,
  ignore.case = FALSE, perl = FALSE,
  fixed = FALSE, useBytes = FALSE
)

grep 和 grepl 是一对字符串查询函数,查看字符串向量 x 中是否包含正则表达式 pattern 描述的内容

  • ignore.case: TRUE 表示忽略大小写,FALSE 表示匹配的时候区分大小写
  • fixed = TRUE 表示启用 literal regular expression 字面正则表达式,默认情况下fixed = FALSE
  • grep 函数返回匹配到的字符串向量x的元素的下标,如果 value=TRUE 则返回下标对应的值
  • grepl 函数返回一个逻辑向量,检查字符串向量x中的每个元素是否匹配到,匹配到返回 TRUE,没有匹配到返回 FALSE
# 返回下标位置
grep("[a-z]", letters)
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## [26] 26
# 返回查询到的值
grep("[a-z]", letters, value = TRUE)
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
## [20] "t" "u" "v" "w" "x" "y" "z"

继续举例子

grep(x = c("apple", "banana"), pattern = "a")
## [1] 1 2
grep(x = c("apple", "banana"), pattern = "b")
## [1] 2
grep(x = c("apple", "banana"), pattern = "a", value = TRUE)
## [1] "apple"  "banana"
grep(x = c("apple", "banana"), pattern = "b", value = TRUE)
## [1] "banana"

关于 grepl 函数的使用例子

grepl(x = c("apple", "banana"), pattern = "a")
## [1] TRUE TRUE
grepl(x = c("apple", "banana"), pattern = "b")
## [1] FALSE  TRUE

R 语言是用字符串来表示正则表达式的,但是正则表达式不是字符串,字符串的构造类似算术表达式

在 R 里面分别表示 a\\b 和 a\b

writeLines(c("a\\\\b", "a\\b"))
## a\\b
## a\b

下面在 R 里面分别匹配字符串 a\\b 和 a\b 中的 \\ 和 \

# 匹配字符串中的一个反斜杠
grep(x = c("a\\\\b", "a\\b"), pattern = "\\", value = TRUE, fixed = TRUE)
## [1] "a\\\\b" "a\\b"
grep(x = c("a\\\\b", "a\\b"), pattern = "\\\\", value = TRUE, fixed = FALSE)
## [1] "a\\\\b" "a\\b"
# 匹配字符串中的两个反斜杠
grep(x = c("a\\\\b", "a\\b"), pattern = "\\\\", value = TRUE, fixed = TRUE)
## [1] "a\\\\b"
grep(x = c("a\\\\b", "a\\b"), pattern = "\\\\\\\\", value = TRUE, fixed = FALSE)
## [1] "a\\\\b"
# 匹配字符串中的两个反斜杠 \\
grepl(x = "a\\\\b", pattern = "\\\\\\\\", fixed = FALSE)
## [1] TRUE
grepl(x = "a\\\\b", pattern = "\\\\\\\\", fixed = TRUE)
## [1] FALSE
grepl(x = "a\\\\b", pattern = "\\\\", fixed = TRUE)
## [1] TRUE
regexpr(pattern, text,
  ignore.case = FALSE, perl = FALSE,
  fixed = FALSE, useBytes = FALSE
)
gregexpr(pattern, text,
  ignore.case = FALSE, perl = FALSE,
  fixed = FALSE, useBytes = FALSE
)
regexec(pattern, text,
  ignore.case = FALSE, perl = FALSE,
  fixed = FALSE, useBytes = FALSE
)       

当启用 perl=TRUE 时, 函数 regexpr 和 gregexpr 支持 Python 环境下的命名捕获(named captures),但是不支持长向量的输入。如果一个分组被命名了,如 (?<first>[A-Z][a-z]+) 那么匹配到的位置按命名返回。函数 sub 不支持命名反向引用 (Named backreferences)

函数 regmatches 用来提取函数regexpr, gregexpr 和 regexec 匹配到的子字符串

useBytes = FALSE 匹配位置和长度默认是按照字符级别来的,如果 useBytes = TRUE 则是按照逐个字节的匹配结果

如果使用到了 命名捕获 则会返回更多的属性 “capture.start”,“capture.length” 和 “capture.names”,分别表示捕获的起始位置、捕获的长度和捕获的命名。

  • regexpr 函数返回一个整型向量,第一次匹配的初始位置,-1 表示没有匹配到,返回的属性 match.length 表示匹配的字符数量,是一个整型向量,向量长度是匹配的文本的长度,-1 表示没有匹配到
text <- c("Hellow, Adam!", "Hi, Adam!", "How are you, Adam.")
regexpr("Adam", text)
## [1]  9  5 14
## attr(,"match.length")
## [1] 4 4 4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
txt <- c(
  "The", "licenses", "for", "most", "software", "are",
  "designed", "to", "take", "away", "your", "freedom",
  "to", "share", "and", "change", "it.",
  "", "By", "contrast,", "the", "GNU", "General", "Public", "License",
  "is", "intended", "to", "guarantee", "your", "freedom", "to",
  "share", "and", "change", "free", "software", "--",
  "to", "make", "sure", "the", "software", "is",
  "free", "for", "all", "its", "users"
)
# gregexpr("en", txt)
regexpr("en", txt)
##  [1] -1  4 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2 -1  4
## [26] -1  4 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
## attr(,"match.length")
##  [1] -1  2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2 -1  2
## [26] -1  2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
  • gregexpr 函数返回一个列表,返回列表的长度与字符串向量的长度一样,列表中每个元素的形式与 regexpr 的返回值一样, except that the starting positions of every (disjoint) match are given.
gregexpr("Adam", text)
## [[1]]
## [1] 9
## attr(,"match.length")
## [1] 4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
## 
## [[2]]
## [1] 5
## attr(,"match.length")
## [1] 4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
## 
## [[3]]
## [1] 14
## attr(,"match.length")
## [1] 4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
  • regexec 函数返回一个列表,类似函数gregexpr的返回结果,长度与字符串向量的长度一样,如果没有匹配到就返回 -1,匹配到了就返回一个匹配的初值位置的整型序列,所有子字符串与括号分组的正则表达式的子表达式对应,属性 “match.length” 是一个表示匹配的长度的向量,如果是 -1 表示没有匹配到。位置、长度和属性的解释与 regexpr 一致
regexec("Adam", text)
## [[1]]
## [1] 9
## attr(,"match.length")
## [1] 4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
## 
## [[2]]
## [1] 5
## attr(,"match.length")
## [1] 4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
## 
## [[3]]
## [1] 14
## attr(,"match.length")
## [1] 4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE

由于资源限制(特别是 PCRE)导致的匹配失败,会视为没有匹配,通常伴随一个警告

下面这个将链接分解的例子由 Luke Tierney 提供12

x <- "http://stat.umn.edu:80/xyz"
m <- regexec("^(([^:]+)://)?([^:/]+)(:([0-9]+))?(/.*)", x)
m
## [[1]]
## [1]  1  1  1  8 20 21 23
## attr(,"match.length")
## [1] 26  7  4 12  3  2  4
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE

这里 x 是一个字符串,所以函数 regexec 返回的列表长度为1,正则表达式 ^(([^:]+)://)?([^:/]+)(:([0-9]+))?(/.*) 括号分组匹配到了7次,第一次匹配整个字符串,所以起始位置是1,而匹配长度是26,即整个字符串的长度,读者可以调用函数 nchar(x) 算一下,如果你愿意手动数一下也可以哈!余下不一一介绍,可以根据返回结果和图4.1一起看,最后还可以调用regmatches函数抽取匹配到的结果

regmatches(x, m)
## [[1]]
## [1] "http://stat.umn.edu:80/xyz" "http://"                   
## [3] "http"                       "stat.umn.edu"              
## [5] ":80"                        "80"                        
## [7] "/xyz"

我们可以在 https://regex101.com/ 上测试表达式,如图4.1所示,表达式 ^(([^:]+)://)?([^:/]+)(:([0-9]+))?(/.*) 包含7个组,每个组的匹配结果见图的右下角,这样我们不难理解,函数 regmatches 返回的第列表中,第3个位置是传输协议 protocol http ,第4个位置是主机 host stat.umn.edu, 第6个位置是端口 port 80 ,第7个位置是路径 path /xyz,所以函数 regmatches 的作用就是根据函数 regexec 匹配的结果抽取子字符串。

正则表达式匹配结果

图 4.1: 正则表达式匹配结果

进一步,我们可以用 regmatches 函数抽取 URL 的部分内容,如前面提到的传输协议,主机等

URL_parts <- function(x) {
  m <- regexec("^(([^:]+)://)?([^:/]+)(:([0-9]+))?(/.*)", x)
  parts <- do.call(
    rbind,
    lapply(regmatches(x, m), `[`, c(3L, 4L, 6L, 7L))
    # 3,4,6,7是索引位置
  )
  colnames(parts) <- c("protocol", "host", "port", "path")
  parts
}
URL_parts(x)
##      protocol host           port path  
## [1,] "http"   "stat.umn.edu" "80" "/xyz"

目前还没有 gregexec 函数,但是可以模拟一个,首先用 gregexpr 函数返回匹配的位置,regmatches 抽取相应的值,然后用 regexec 作用到每一个提取的值,做再一次匹配和值的抽取,实现了全部的匹配。另一个例子

## There is no gregexec() yet, but one can emulate it by running
## regexec() on the regmatches obtained via gregexpr().  E.g.:
pattern <- "([[:alpha:]]+)([[:digit:]]+)"
s <- "Test: A1 BC23 DEF456"
gregexpr(pattern, s)
## [[1]]
## [1]  7 10 15
## attr(,"match.length")
## [1] 2 4 6
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
regmatches(s, gregexpr(pattern, s))
## [[1]]
## [1] "A1"     "BC23"   "DEF456"
lapply(
  regmatches(s, gregexpr(pattern, s)),
  function(e) regmatches(e, regexec(pattern, e))
)
## [[1]]
## [[1]][[1]]
## [1] "A1" "A"  "1" 
## 
## [[1]][[2]]
## [1] "BC23" "BC"   "23"  
## 
## [[1]][[3]]
## [1] "DEF456" "DEF"    "456"

  1. https://homepage.divms.uiowa.edu/~luke/R/regexp.html↩︎