
處理文本是每一種計算機語言都應該具備的功能,但不是每一種語言都側重于處理文本。R語言是統計的語言,處理文本不是它的強項,perl語言這方面的功能比R不知要強多少倍。幸運的是R語言的可擴展能力很強,DNA/RNA/AA等生物序列現在已經可以使用R來處理。
R語言處理文本的能力雖然不強,但適當用用還是可以大幅提高工作效率的,而且有些文本操作還不得不用。高效處理文本少不了正則表達式(regular expression),雖然R在這方面先天不足,但它處理字符串的絕大多數函數還都使用正則表達式。
Table of Contents
1 正則表達式簡介
2 字符數統計和字符翻譯
2.1 nchar和length
2.2 tolower,toupper和chartr
3 字符串連接
3.1 paste函數
4 字符串拆分
4.1 strsplit函數
5 字符串查詢:
5.1 grep和grepl函數:
5.2 regexpr、gregexpr和regexec
6 字符串替換
6.1 sub和gsub函數
7 字符串提取
7.1 substr和substring函數
8 其他:
8.1 strtrim函數
8.2 strwrap函數
8.3 match和charmatch
1 正則表達式簡介
正則表達式不是R的專屬內容,這里只做簡單介紹,更詳細的內容請查閱其他文章。
正則表達式是用于描述/匹配一個文本集合的表達式:
所有英文字母、數字和很多可顯示的字符本身就是正則表達式,用于匹配它們自己。比如 “a” 就是匹配字母 “a” 的正則表達式
一些特殊的字符在正則表達式中不在用來描述它自身,它們在正則表達式中已經被“轉義”,這些字符稱為“元字符”。perl類型的正則表達式中被轉 義的字符有:. \ | ( ) [ ] { } ^ $ * + ?。被轉義的字符已經有特殊的意義,如點號 . 表示任意字符;方括號表示選擇方括號中的任意一個(如[a-z] 表示任意一個小寫字符);^ 放在表達式開始出表示匹配文本開始位置,放在方括號內開始處表示非方括號內的任一字符;大括號表示前面的字符或表達式的重復次數;| 表示可選項,即 | 前后的表達式任選一個。
如果要在正則表達式中表示元字符本身,比如我就要在文本中查找問號“?”, 那么就要使用引用符號(或稱換碼符號),一般是反斜杠 “\”。需要注意的是,在R語言中得用兩個反斜杠即 “\\”,如要匹配括號就要寫成 “\\(\\)”
不同語言或應用程序(事實上很多規則都通用)定義了一些特殊的元字符用于表示某類字符,如 \d 表示數字0-9, \D 表示非數字,\s 表示空白字符(包括空格、制表符、換行符等),\S 表示非空白字符,\w 表示字(字母和數字),\W 表示非字,\< 和 \> 分別表示以空白字符開始和結束的文本。
正則表達式符號運算順序:圓括號括起來的表達式最優先,然后是表示重復次數的操作(即:* + {} ),接下來是連接運算(其實就是幾個字符放在一起,如abc),最后是表示可選項的運算(|)。所以 “foot|bar” 可以匹配“foot”或者“bar”,但是“foot|ba{2}r”匹配的是“foot”或者“baar”。
2 字符數統計和字符翻譯
2.1 nchar和length
nchar這個函數簡單,統計向量中每個元素的字符個數,注意這個函數和length函數的差別:nchar是向量元素的字符個數,而length是向量長度(向量元素的個數)。其他沒什么需要說的。
x <- c("Hellow", "World", "!") nchar(x)
## [1] 6 5 1
length("")
## [1] 1
nchar("")
## [1] 0
2.2 tolower,toupper和chartr
這三個函數用法也很簡單:
DNA <- "AtGCtttACC" tolower(DNA)
## [1] "atgctttacc"
toupper(DNA)
## [1] "ATGCTTTACC"
chartr("Tt", "Uu", DNA)
## [1] "AuGCuuuACC"
chartr("Tt", "UU", DNA)
## [1] "AUGCUUUACC"
3 字符串連接
3.1 paste函數
paste應該是R中最常用字符串函數了,也是R字符串處理函數里面非常純的不使用正則表達式的函數(因為用不著)。它相當于其他語言的strjoin,但是功能更強大。它把向量連成字串向量,其他類型的數據會轉成向量,但不一定是你要的結果:
paste("CK", 1:6, sep = "")
## [1] "CK1" "CK2" "CK3" "CK4" "CK5" "CK6"
x <- list(a = "aaa", b = "bbb", c = "ccc") y <- list(d = 1, e = 2) paste(x, y, sep = "-") #較短的向量被循環使用
## [1] "aaa-1" "bbb-2" "ccc-1"
z <- list(x, y) paste("T", z, sep = ":")
## [1] "T:list(a = \"aaa\", b = \"bbb\", c = \"ccc\")" ## [2] "T:list(d = 1, e = 2)"
短向量重復使用,列表數據只有一級列表能有好的表現,能不能用看自己需要。會得到什么樣的結果是可以預知的,用as.character函數看吧,這又是一個字符串處理函數:
as.character(x)
## [1] "aaa" "bbb" "ccc"
as.character(z)
## [1] "list(a = \"aaa\", b = \"bbb\", c = \"ccc\")" ## [2] "list(d = 1, e = 2)"
paste函數還有一個用法,設置collapse參數,連成一個字符串:
paste(x, y, sep = "-", collapse = "; ")
## [1] "aaa-1; bbb-2; ccc-1"
paste(x, collapse = "; ")
## [1] "aaa; bbb; ccc"
4 字符串拆分
4.1 strsplit函數
strsplit函數使用正則表達式,使用格式為:
strsplit(x, split, fixed = FALSE, perl = FALSE, useBytes = FALSE)
參數x為字串向量,每個元素都將單獨進行拆分。
參數split為拆分位置的字串向量,默認為正則表達式匹配(fixed=FALSE)。如果你沒接觸過正則表達式,設置fixed=TRUE,表示使用普通文本匹配或正則表達式的精確匹配。普通文本的運算速度快。
perl=TRUE/FALSE的設置和perl語言版本有關,如果正則表達式很長,正確設置表達式并且使用perl=TRUE可以提高運算速度。
參數useBytes設置是否逐個字節進行匹配,默認為FALSE,即按字符而不是字節進行匹配。
下面的例子把一句話按空格拆分為單詞:
text <- "Hello Adam!\nHello Ava!" strsplit(text, " ")
## [[1]] ## [1] "Hello" "Adam!\nHello" "Ava!"
R語言的字符串事實上也是正則表達式,上面文本中的\n在圖形輸出中是被解釋為換行符的。
strsplit(text, "\\s")
## [[1]] ## [1] "Hello" "Adam!" "Hello" "Ava!"
strsplit得到的結果是列表,后面要怎么處理就得看情況而定了:
class(strsplit(text, "\\s"))
## [1] "list"
有一種情況很特殊:如果split參數的字符長度為0,得到的結果就是一個個的字符:
strsplit(text, "")
## [[1]] ## [1] "H" "e" "l" "l" "o" " " "A" "d" "a" "m" "!" "\n" "H" "e" ## [15] "l" "l" "o" " " "A" "v" "a" "!"
從這里也可以看到R把 \n 是當成一個字符來處理的。
5 字符串查詢:
5.1 grep和grepl函數:
這兩個函數返回向量水平的匹配結果,不涉及匹配字符串的詳細位置信息。
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)
雖然參數看起差不多,但是返回的結果不一樣。下來例子列出C:\windows目錄下的所有文件,然后用grep和grepl查找exe文件:
files <- list.files("c:/windows") grep("\\.exe$", files)
## [1] 8 28 30 35 36 58 69 99 100 102 111 112 115 117
grepl("\\.exe$", files)
## [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE ## [12] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ## [23] FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE ## [34] FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ## [45] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ## [56] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ## [67] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ## [78] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ## [89] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE ## [100] TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE ## [111] TRUE TRUE FALSE FALSE TRUE FALSE TRUE FALSE
grep僅返回匹配項的下標,而grepl返回所有的查詢結果,并用邏輯向量表示有沒有找到匹配。兩者的結果用于提取數據子集的結果都一樣:
files[grep("\\.exe$", files)]
## [1] "bfsvc.exe" "explorer.exe" "fveupdate.exe" "HelpPane.exe" ## [5] "hh.exe" "notepad.exe" "regedit.exe" "twunk_16.exe" ## [9] "twunk_32.exe" "uninst.exe" "winhelp.exe" "winhlp32.exe" ## [13] "write.exe" "xinstaller.exe"
files[grepl("\\.exe$", files)]
## [1] "bfsvc.exe" "explorer.exe" "fveupdate.exe" "HelpPane.exe" ## [5] "hh.exe" "notepad.exe" "regedit.exe" "twunk_16.exe" ## [9] "twunk_32.exe" "uninst.exe" "winhelp.exe" "winhlp32.exe" ## [13] "write.exe" "xinstaller.exe"
5.2 regexpr、gregexpr和regexec
這三個函數返回的結果包含了匹配的具體位置和字符串長度信息,可以用于字符串的提取操作。
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(,"useBytes") ## [1] TRUE
gregexpr("Adam", text)
## [[1]] ## [1] 9 ## attr(,"match.length") ## [1] 4 ## attr(,"useBytes") ## [1] TRUE ## ## [[2]] ## [1] 5 ## attr(,"match.length") ## [1] 4 ## attr(,"useBytes") ## [1] TRUE ## ## [[3]] ## [1] 14 ## attr(,"match.length") ## [1] 4 ## attr(,"useBytes") ## [1] TRUE
regexec("Adam", text)
## [[1]] ## [1] 9 ## attr(,"match.length") ## [1] 4 ## ## [[2]] ## [1] 5 ## attr(,"match.length") ## [1] 4 ## ## [[3]] ## [1] 14 ## attr(,"match.length") ## [1] 4
6 字符串替換
6.1 sub和gsub函數
雖然sub和gsub是用于字符串替換的函數,但嚴格地說R語言沒有字符串替換的函數,因為R語言不管什么操作對參數都是傳值不傳址。
text
## [1] "Hellow, Adam!" "Hi, Adam!" "How are you, Adam."
sub(pattern = "Adam", replacement = "world", text)
## [1] "Hellow, world!" "Hi, world!" "How are you, world."
text
## [1] "Hellow, Adam!" "Hi, Adam!" "How are you, Adam."
可以看到:雖然說是“替換”,但原字符串并沒有改變,要改變原變量我們只能通過再賦值的方式。 sub和gsub的區別是前者只做一次替換(不管有幾次匹配),而gsub把滿足條件的匹配都做替換:
sub(pattern = "Adam|Ava", replacement = "world", text)
## [1] "Hellow, world!" "Hi, world!" "How are you, world."
gsub(pattern = "Adam|Ava", replacement = "world", text)
## [1] "Hellow, world!" "Hi, world!" "How are you, world."
sub和gsub函數可以使用提取表達式(轉義字符+數字)讓部分變成全部:
sub(pattern = ".*(Adam).*", replacement = "\\1", text)
## [1] "Adam" "Adam" "Adam"
7 字符串提取
7.1 substr和substring函數
substr和substring函數通過位置進行字符串拆分或提取,它們本身并不使用正則表達式,但是結合正則表達式函數regexpr、gregexpr或regexec使用可以非常方便地從大量文本中提取所需信息。兩者的參數設置基本相同:
substr(x, start, stop) substring(text, first, last = 1000000L)
x均為要拆分的字串向量
start/first 為截取的起始位置向量
stop/last 為截取字串的終止位置向量
但它們的返回值的長度(個數)有差 別:
substr返回的字串個數等于第一個參數的長度
而substring返回字串個數等于三個參數中最長向量長度,短向量循環使用。
先看第1參數(要 拆分的字符向量)長度為1例子:
x <- "123456789" substr(x, c(2, 4), c(4, 5, 8))
## [1] "234"
substring(x, c(2, 4), c(4, 5, 8))
## [1] "234" "45" "2345678"
因為x的向量長度為1,所以substr獲得的結果只有1個字串,即第2和第3個參數向量只用了第一個組合:起始位置2,終止位置4。 而substring的語句三個參數中最長的向量為c(4,5,8),執行時按短向量循環使用的規則第一個參數事實上就是c(x,x,x),第二個參數就成了c(2,4,2),最終截取的字串起始位置組合為:2-4, 4-5和2-8。
請按照這樣的處理規則解釋下面語句運行的結果:
x <- c("123456789", "abcdefghijklmnopq") substr(x, c(2, 4), c(4, 5, 8))
## [1] "234" "de"
substring(x, c(2, 4), c(4, 5, 8))
## [1] "234" "de" "2345678"
用substring函數可以很方便地把DNA/RNA序列進行三聯拆分(用于蛋白質翻譯):
bases <- c("A", "T", "G", "C") DNA <- paste(sample(bases, 12, replace = T), collapse = "") DNA
## [1] "GCAGCGCATATG"
substring(DNA, seq(1, 10, by = 3), seq(3, 12, by = 3))
## [1] "GCA" "GCG" "CAT" "ATG"
用regexpr、gregexpr或regexec函數獲得位置信息后再進行字符串提取的操作可以自己試試看。
8 其他:
8.1 strtrim函數
用于將字符串修剪到特定的顯示寬度,其用法為strtrim(x, width),返回字符串向量的長度等于x的長度。因為是“修剪”,所以只能去掉多余的字符不能增加其他額外的字符:如果字符串本身的長度小于 width,得到的是原字符串,別指望它會用空格或其他什么字符補齊:
strtrim(c("abcdef", "abcdef", "abcdef"), c(1, 5, 10))
## [1] "a" "abcde" "abcdef"
strtrim(c(1, 123, 1234567), 4)
## [1] "1" "123" "1234"
8.2 strwrap函數
該函數把一個字符串當成一個段落的文字(不管字符串中是否有換行符),按照段落的格式(縮進和長度)和斷字方式進行分行,每一行是結果中的一個字符串。例如:
str1 <- "Each character string in the input is first split into paragraphs\n(or lines containing whitespace only). The paragraphs are then\nformatted by breaking lines at word boundaries. The target\ncolumns for wrapping lines and the indentation of the first and\nall subsequent lines of a paragraph can be controlled\nindependently." str2 <- rep(str1, 2)strwrap(str2, width = 80, indent = 2)
## [1] " Each character string in the input is first split into paragraphs (or lines" ## [2] "containing whitespace only). The paragraphs are then formatted by breaking" ## [3] "lines at word boundaries. The target columns for wrapping lines and the" ## [4] "indentation of the first and all subsequent lines of a paragraph can be" ## [5] "controlled independently." ## [6] " Each character string in the input is first split into paragraphs (or lines" ## [7] "containing whitespace only). The paragraphs are then formatted by breaking" ## [8] "lines at word boundaries. The target columns for wrapping lines and the" ## [9] "indentation of the first and all subsequent lines of a paragraph can be" ## [10] "controlled independently."
simplify參數用于指定結果的返回樣式,默認為TRUE,即結果中所有的字符串都按順序放在一個字符串向量中(如上);如果為FALSE,那么結果將是列表。另外一個參數exdent用于指定除第一行以外的行縮進:
strwrap(str1, width = 80, indent = 0, exdent = 2)
## [1] "Each character string in the input is first split into paragraphs (or lines" ## [2] " containing whitespace only). The paragraphs are then formatted by breaking" ## [3] " lines at word boundaries. The target columns for wrapping lines and the" ## [4] " indentation of the first and all subsequent lines of a paragraph can be" ## [5] " controlled independently."
8.3 match和charmatch
match("xx", c("abc", "xx", "xxx", "xx"))
## [1] 2
match(2, c(3, 1, 2, 4))
## [1] 3
charmatch("xx", "xx")
## [1] 1
charmatch("xx", "xxa")
## [1] 1
charmatch("xx", "axx")
## [1] NA
match按向量進行運算,返回第一次匹配的元素的位置(如果有),非字符向量也可用。charmatch函數真坑爹。其他不看了,其實有正則表達式就足夠。
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
CDA數據分析師證書考試體系(更新于2025年05月22日)
2025-05-26解碼數據基因:從數字敏感度到邏輯思維 每當看到超市貨架上商品的排列變化,你是否會聯想到背后的銷售數據波動?三年前在零售行 ...
2025-05-23在本文中,我們將探討 AI 為何能夠加速數據分析、如何在每個步驟中實現數據分析自動化以及使用哪些工具。 數據分析中的AI是什么 ...
2025-05-20當數據遇見人生:我的第一個分析項目 記得三年前接手第一個數據分析項目時,我面對Excel里密密麻麻的銷售數據手足無措。那些跳動 ...
2025-05-20在數字化運營的時代,企業每天都在產生海量數據:用戶點擊行為、商品銷售記錄、廣告投放反饋…… 這些數據就像散落的拼圖,而相 ...
2025-05-19在當今數字化營銷時代,小紅書作為國內領先的社交電商平臺,其銷售數據蘊含著巨大的商業價值。通過對小紅書銷售數據的深入分析, ...
2025-05-16Excel作為最常用的數據分析工具,有沒有什么工具可以幫助我們快速地使用excel表格,只要輕松幾步甚至輸入幾項指令就能搞定呢? ...
2025-05-15數據,如同無形的燃料,驅動著現代社會的運轉。從全球互聯網用戶每天產生的2.5億TB數據,到制造業的傳感器、金融交易 ...
2025-05-15大數據是什么_數據分析師培訓 其實,現在的大數據指的并不僅僅是海量數據,更準確而言是對大數據分析的方法。傳統的數 ...
2025-05-14CDA持證人簡介: 萬木,CDA L1持證人,某電商中廠BI工程師 ,5年數據經驗1年BI內訓師,高級數據分析師,擁有豐富的行業經驗。 ...
2025-05-13CDA持證人簡介: 王明月 ,CDA 數據分析師二級持證人,2年數據產品工作經驗,管理學博士在讀。 學習入口:https://edu.cda.cn/g ...
2025-05-12CDA持證人簡介: 楊貞璽 ,CDA一級持證人,鄭州大學情報學碩士研究生,某上市公司數據分析師。 學習入口:https://edu.cda.cn/g ...
2025-05-09CDA持證人簡介 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度、美團、阿里等 ...
2025-05-07相信很多做數據分析的小伙伴,都接到過一些高階的數據分析需求,實現的過程需要用到一些數據獲取,數據清洗轉換,建模方法等,這 ...
2025-05-06以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda.cn/g ...
2025-04-30CDA持證人簡介: 邱立峰 CDA 數據分析師二級持證人,數字化轉型專家,數據治理專家,高級數據分析師,擁有豐富的行業經驗。 ...
2025-04-29CDA持證人簡介: 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度,美團,阿里等 ...
2025-04-28CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-27數據分析在當今信息時代發揮著重要作用。單因素方差分析(One-Way ANOVA)是一種關鍵的統計方法,用于比較三個或更多獨立樣本組 ...
2025-04-25CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-25