R語言-正則表達式


R語言中正則表達式

內容概覽

  有時候我們要處理的是非結構化的數據,例如網頁或是電郵資料,那么就需要用R來抓取所需的字符串,整理為進一步處理的數據形式。R語言中有一整套可以用來處理字符的函數,在之前的 博文 中已經有所涉及。但真正的要用好字符處理函數,則不得不用到正則表達式。 正則表達式(Regular Expression、regexp) 是指一種用來描述一定數量文本的模式。熟練掌握正則表達式能使你隨心所欲的操作文本來達成目標。其實學習正則表達式並沒有想像中的那么困難。最好方法是從例子開始,然后多練習,多使用。網絡上已經有許多不錯的參考資料,例如 這篇 或 那篇 。本文假設你對正則表達式有了基本的了解,下面我們來看看如何在R里面來使用它。

  R語言處理文本的能力雖然不強,但適當用用還是可以大幅提高工作效率的,而且有些文本操作還不得不用。高效處理文本少不了正則表達式(regular expression),雖然R在這方面先天不高效,但它處理字符串的絕大多數函數都使用正則表達式。

  • 正則表達式簡介:

      正則表達式不是R的專屬內容,這里也只簡單介紹,更詳細的內容請查閱其他文章。正則表達式是用於描述/匹配一個文本集合的表達式。

      1.  所有英文字母、數字和很多可顯示的字符本身就是正則表達式,用於匹配它們自己。比如 'a' 就是匹配字母 'a' 的正則表達式
      
      2.  一些特殊的字符在正則表達式中不在用來描述它自身,它們在正則表達式中已經被“轉義”,這些字符稱為“元字符”。perl類型的正則表達式中被轉義的字符有:. \ | ( ) [ ] { } ^ $ * + ?。被轉義的字符已經有特殊的意義,如點號 . 表示任意字符;方括號表示選擇方括號中的任意一個(如[a-z] 表示任意一個小寫字符);^ 放在表達式開始出表示匹配文本開始位置,放在方括號內開始處表示非方括號內的任一字符;大括號表示前面的字符或表達式的重復次數;| 表示可選項,即 | 前后的表達式任選一個。
      
      3.  如果要在正則表達式中表示元字符本身,比如我就要在文本中查找問號‘?’, 那么就要使用引用符號(或稱換碼符號),一般是反斜杠 '\'。需要注意的是,在R語言中得用兩個反斜杠即 ‘\\’,如要匹配括號就要寫成 ’\\(\\)‘
      
      4.  不同語言或應用程序(事實上很多規則都通用)定義了一些特殊的元字符用於表示某類字符,如 \d 表示數字0-9, \D 表示非數字,\s 表示空白字符(包括空格、制表符、換行符等),\S 表示非空白字符,\w 表示字(字母和數字),\W 表示非字,\< 和 \> 分別表示以空白字符開始和結束的文本。
      
      5.  正則表達式符號運算順序:圓括號括起來的表達式最優先,然后是表示重復次數的操作(即:* + {} ),接下來是連接運算(其實就是幾個字符放在一起,如abc),最后是表示可選項的運算(|)。所以 'foot|bar' 可以匹配’foot‘或者’bar‘,但是 'foot|ba{2}r'匹配的是’foot‘或者’baar‘。
    
  • 關於正則表達式

      正則表達式是編程語言的特色,也是一大難點,幾乎各類編程語言都有數據自己的正則表達式,但方法都大同小異,R里面有關正則表達式里面選擇采用具有特色的perl語言風格的正則表達式。掌握好這些正則表達式的使用方法,就可以輕易地完成字符串處理任務。正則表達式,又稱正規表示法、常規表示法,它使用單個字符串來描述、匹配一系列符合某個句法規則的字符串。在很多文本編輯器里,正則表達式通常被用來檢索、替換那些符合某個模式的文本。下面列出正則表達式常用模式:

      [0-9] 匹配所有數字字符
      [^0-9] 匹配所有非數字字符 
      [^a-z] 匹配所有非小寫字母字符 
      ^ 匹配字符開頭的字符
      
      $   匹配字符結尾的字符 
      \d  匹配一個數字的字符
      \d+ 匹配多個數字字符串
      \D  非數字,其他同 \d 
      \w  英文字母或數字的字符串,和 [a-zA-Z0-9] 語法一樣
      \W  非英文字母或數字的字符串
      \s  空格
      \S  非空格
      \b  匹配以英文字母,數字為邊界的字符串 
      \B  匹配不以英文字母,數值為邊界的字符串
      
      .  匹配除換行符以外的所有單個字符 
      […] 字符組 匹配單個列出的字符
      x? 匹配 0 次或一次 x 字符串
      x* 匹配 0 次或多次 x 字符串,但匹配可能的最少次數 
      x+ 匹配 1 次或多次 x 字符串,但匹配可能的最少次數 
      .* 匹配 0 次或一次的任何字符 
      .+ 匹配 1 次或多次的任何字符 
      {m} 匹配剛好是 m 個 的指定字符串 
      {m,n} 匹配在 m個 以上 n個 以下 的指定字符串 
      {m,} 匹配 m個 以上 的指定字符串 
      [] 匹配符合 [] 內的字符 
      [^] 匹配不符合 [] 內的字符
    
  • 常用表達式語法結構

      grep, grepl, regexpr, gregexpr 函數在字符串向量中尋找特定的匹配模式pattern,具體區別在參數的選擇。sub, gsub 分別用於替換單個或者全部的匹配模式,這里g意味着global。

      詳細語法:
    
      	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)
      	
      	sub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE,fixed = FALSE, useBytes = FALSE)
      	
      	gsub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE,fixed = FALSE, useBytes = FALSE)
      	
      	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,fixed = FALSE, useBytes = FALSE)
    
      參數說明:
      
      	pattern : 用於匹配的正則表達式。只接受一個元素。
      	x, text : 被匹配的字符串(向量)。
      	ignore.case : 是否大小寫敏感,默認為FALSE
      	perl : 是否兼容Perl語言的正則表達式,默認FALSE
      	value : 是否返回匹配的值。默認FALSE,那么將會返回向量的索引indice; 如果為TRUE,則返回被匹配的字符串
      	fixed : 如果TRUE,則匹配整個元素。默認FALSE
      	useBytes : 是否使用byte-by-byte還是character-by-character,默認FALSE
      	invert : 是否取反,如果TRUE,則返回未匹配的索引indices或值values
      	replacement : 適用於sub和gsub。只接受一個元素。
      	grep(value = FALSE) 返回匹配向量的索引(若invert = TRUE,情況相反)
      	grep(value = TRUE) 返回匹配向量的原始值
      	grepl 返回布爾向量,包含是否匹配的信息
      	sub 和 gsub 返回和原先向量同樣長度的新向量.
      	regexpr 返回一個和初始向量text長度保持一致的向量數組,元素為第一次匹配的起點位置(如果沒有匹配成功則顯示-1)同時還附有匹配長度(匹配顯示匹配長度,否則顯示-1),如果想計算bytes的長度,請使用 useBytes = TRUE
      	gregexpr和regexec 均返回一個list列表,經測試內容和regexpr保持一致,但不知其具體區別,望告知
    
  • Example_1

      假設我們有一個字符向量,包括了三個字符串。我們的目標是從中抽取電郵地址。R語言中很多字符函數都能識別正則表達式,而最重要的函數就是gregexpr()。該函數的第一個參數是正則表達式,前后需要用引號,對元字符進行轉義時要用\。第二個參數是等待處理的文本。那么用如下三行代碼,我們從word字符向量中得到一個列表,其中第一項元素中的5表示電郵地址從第5個字符位置開始,24表示電郵地址長度為24。

      > word <- c('abc noboby@stat.berkeley.edu','text with no email','first me@mything.com also you@yourspace.com')
      > pattern <- '[-A-Za-z0-9_.%]+@[-A-Za-z0-9_.%]+\\.[A-Za-z]+'
      > pattern
      [1] "[-A-Za-z0-9_.%]+@[-A-Za-z0-9_.%]+\\.[A-Za-z]+"
      > (gregout <- gregexpr(pattern,word))
      [[1]]
      [1] 5
      attr(,"match.length")
      [1] 24
      attr(,"useBytes")
      [1] TRUE
      
      [[2]]
      [1] -1
      attr(,"match.length")
      [1] -1
      attr(,"useBytes")
      [1] TRUE
      
      [[3]]
      [1]  7 27
      attr(,"match.length")
      [1] 14 17
      attr(,"useBytes")
      [1] TRUE
      
      > 
    

      下一步我們需要將電郵地址抽取出來,此時配合substr函數,即可根據需要字符串的位置來提取子集。

      > substr(word[1],gregout[[1]],gregout[[1]]+attr(gregout[[1]],'match.length')-1)
      [1] "noboby@stat.berkeley.edu"
      > 
    

      更方便的使用方式是根據上述方法建立一個自定義函數getcontent,參數s表示待處理的文本,參數g表示的是通過gregexpr函數處理后的結果。這個函數我們在后面還會用到。

      > getcontent <- function(s,g){
      +   substring(s,g,g+attr(g,'match.length')-1)
      + }
      > getcontent(word[1],gregout[[1]])	
      [1] "noboby@stat.berkeley.edu"
      > getcontent(word[2],gregout[[2]])	
      [1] ""
      > getcontent(word[3],gregout[[3]])
      [1] "me@mything.com"    "you@yourspace.com"
      > 
    
  • Example_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 
    
  • Example_3

      這里出現的replacement參數,在x中搜索pattern,並以文本replacement將其替換;其他的各個參數和grep的作用相同。

      > p="Who wins the prize?"
      > sub("Who",replacement="James",sub("[\\?]","!",p,perl=T))
      [1] "James wins the prize!"
    

      gsub和sub函數的不同之處在於sub函數只替換其匹配文本中第一次出現的匹配,而gsub為globe sub全局匹配替換,即替換匹配到的所有匹配值。

      > txt <- "a test of capitalizing"
      > gsub("(\\w)(\\w*)", "\\U\\1\\L\\2", txt, perl=TRUE)
      [1] "A Test Of Capitalizing"
      
      > gsub("\\b(\\w)", "\\U\\1", txt, perl = T)
      [1] "A Test Of Capitalizing"
    

      perl正則表達式中,\為轉義符,\w為元字符,匹配數字型的字符;* 為匹配0個或多個x,\U:大寫字符,直到字符串末尾或碰到\E,\L:小寫字符,直到字符串末尾或碰到\E,\b:匹配以英文字母,數字為邊界的字符串, \1,\2分別為匹配第一組括號和第二組括號。使用以上的gsub替換,可以將文本每個單詞的首字母大寫。

      regexpr,gregexpr,regexec,它們可以返回和text相同長度的向量,包括不匹配的值

      > m=c("e","the","end","of","line")
      > regexpr("e",m)
      [1]  1  3  1 -1  4
    
      attr(,"match.length")
      [1]  1  1  1 -1  1
      
      attr(,"useBytes")
      [1] TRUE
    
  • Example_4

      從regexpr()的返回結果看,返回結果是個整數型向量,但是它還具有兩個額外的屬性(attributes),分別是匹配字段的長度和是否按字節進行匹配;regexpr()的返回結果為-1和1,其中-1表示沒有匹配上,1表示text中第2個元素中的第一個字符被匹配上,且匹配字符的長度為2(屬性值中提供);gregexpr()的返回結果中包含了全部的匹配結果的位置信息,而regexpr()只返回了向量text里每個元素中第一個匹配的位置信息,gregexpr()的返回結果類型是list類型對象;regexec()的返回結果基本與regexpr()類似,只返回了第一個匹配的位置信息,但其結果是一個list類型的對象,並且列表里面的元素少了一個屬性值,即attr(,“useBytes”)。

      #### grep 和 grepl
      text <- c("We are the world", "we are the children")
      grep("We", text)  #向量text中的哪些元素匹配了單詞'We'
      ## [1] 1
      grep("We", text, invert = T)  #向量text中的哪些元素沒有匹配單詞'We'
      ## [1] 2
      grep("we", text, ignore.case = T)  #匹配時忽略大小寫
      ## [1] 1 2
      grepl("are", text)  #向量text中的每個元素是否匹配了單詞'We',即只返回TRUE或FALSE
      ## [1] TRUE TRUE
    
      #### regexpr、gregexpr和regexec
      text <- c("We are the world", "we are the children")
      regexpr("e", text)
      ## [1] 2 2
      ## attr(,"match.length")
      ## [1] 1 1
      ## attr(,"useBytes")
      ## [1] TRUE
      class(regexpr("e", text))
      ## [1] "integer"
      gregexpr("e", text)
      ## [[1]]
      ## [1]  2  6 10
      ## attr(,"match.length")
      ## [1] 1 1 1
      ## attr(,"useBytes")
      ## [1] TRUE
      ## 
      ## [[2]]
      ## [1]  2  6 10 18
      ## attr(,"match.length")
      ## [1] 1 1 1 1
      ## attr(,"useBytes")
      ## [1] TRUE
      class(gregexpr("e", text))
      ## [1] "list"
      regexec("e", text)
      ## [[1]]
      ## [1] 2
      ## attr(,"match.length")
      ## [1] 1
      ## 
      ## [[2]]
      ## [1] 2
      ## attr(,"match.length")
      ## [1] 1
      class(regexec("e", text))
      ## [1] "list"
    

      除了上面的字符串的查詢,有時還會用到完全匹配,這是會用到match(),其命令形式如下: match(x, table, nomatch= NAinteger, incomparables)只有參數x的內容被完全匹配,函數才會返回參數x所在table參數中的下標,否則的話會返回nomatch參數中定義的值(默認是NA)。

      text <- c("We are the world", "we are the children", "we")
      match("we", text)
      ## [1] 3
      match(2, c(3, 4, 2, 8))
      ## [1] 3
      match("xx", c("abc", "xxx", "xx", "xx"))  #只會返回第一個完全匹配的元素的下標
      ## [1] 3
      match(2, c(3, 4, 2, 8, 2))
      ## [1] 3
      match("xx", c("abc", "xxx"))  # 沒有完全匹配的,因此返回NA
      ## [1] NA
    

      此外還有一個charmatch(),其命令形式類似於match,但從下面的例子來看其行為有些古怪。同樣該函數也會返回其匹配字符串所在table中的下標,該函數在進行匹配時,會從table里字符串的最左面(即第一個字符)開始匹配,如果起始位置沒有匹配則返回NA;如果同時部分匹配和完全匹配,則會優先選擇完全匹配;如果同時有多個完全匹配或者多個部分匹配時,則會返回0;如果以上三個都沒有,則返回NA。另外還有一個pmatch(),其功能同charmatch()一樣,僅僅寫法不同。

      charmatch("xx", c("abc", "xxa"))
      ## [1] 2
      charmatch("xx", c("abc", "axx"))  # 從最左面開始匹配
      ## [1] NA
      charmatch("xx", c("xxa", "xxb"))  # 不唯一
      ## [1] 0
      charmatch("xx", c("xxa", "xxb", "xx"))  # 優先選擇完全匹配,盡管有兩個部分匹配
      ## [1] 3
      charmatch(2, c(3, 4, 2, 8))
      ## [1] 3
      charmatch(2, c(3, 4, 2, 8, 2))
      ## [1] 0
    

      不知道這樣一個奇怪的函數在那里能夠用到,真是有點期待!

  • Example_5

      正則匹配是一個非常常用的字符搜索手段,在數據挖掘中起着非常重要的作用。所以雖然它是一種常規手段,但我還是另起一段來專門講述這個概念。

      在R當中,可以使用三種正則:
      
      擴展正則
      基本正則
      Perl風格正則
      
      正則的使用主要涉汲以下7個函數:grep, grepl, sub, gsub, regexpr, gregrexpr, regexec。而象strsplit, apropos以及browseEnv都是基於這7個函數基礎之上的。
      我們先從正則講起。
    

      假設我們現在需要從一堆字符當中找到一個符合一定規則的字符串,比如說從一個表格中找到所有人的email地址,或者說找到一段文字中所有的URL地址,你會如何做呢?嗯,回答肯定是正則了。正則就是做這個用的。我們知道一個email地址通常都是這樣的(最簡單情行),xxxxxx@ppp.ddd,其中,xxxxxx可能是任意字母,數字,以及下划線,點等組成,而ppp.ddd就是一個域名地址。它們之間以@相隔。在正則下是這樣表示,[1]+@[A-Za-z0-9\.-]+\.[A-Za-z]{2,4}$

      > pattern="^[A-Za-z0-9\\._%+-]+@[A-Za-z0-9\\.-]+\\.[A-Za-z]{2,4}$"
      > str<-c("abc","someone@qiuworld.com","efg","anotherone@gmail.com","thirdone@yahoo.cn")
      > #grepl會返回一個邏輯值,l就代表logical, g就代表global
      > grepl(pattern,str)
      [1] FALSE  TRUE FALSE  TRUE  TRUE
      > #grep會返回匹配的id
      > grep(pattern,str)
      [1] 2 4 5
      > #regexpr會返回一個數字,1表示匹配,-1表示不匹配,還會返回兩個屬性,匹配的長度以及是否使用useBytes。useBytes一般很少會使用到false,因為我們不處理寬字符。
      > regexpr(pattern,str)
      [1] -1  1 -1  1  1
      attr(,"match.length")
      [1] -1 20 -1 20 17
      attr(,"useBytes")
      [1] TRUE
    
    
      > #regexec會返回一個list,下面的內容是第一個匹配及其長度
      > regexec("\\w+@\\w+\\.[a-zA-Z]{2,4}","abc@qiuworld.com,efd@qiuworld.com")
      [[1]]
      [1] 1
      attr(,"match.length")
      [1] 16
       
      > #gregexpr也會返回一個list, 下面的內容是每一個匹配及其長度以及useBytes。g就代表global
      > gregexpr("\\w+@\\w+\\.[a-zA-Z]{2,4}","abc@qiuworld.com,efd@qiuworld.com")
      [[1]]
      [1]  1 18
      attr(,"match.length")
      [1] 16 16
      attr(,"useBytes")
      [1] TRUE
      
      > #sub和gsub都用來做正則替換,其區別只在於g所代表的global。sub只替換遇到的第一個匹配,而gsub會替換所有的匹配。
      > #需要注意的是,這里的匹配都是對應的一個字符串而言的,如果是多個字符串,要區別為每一個來單獨對待。
      > sub("\\w+@\\w+\\.[a-zA-Z]{2,4}","sub_function","abc@qiuworld.com,efd@qiuworld.com")
      [1] "sub_function,efd@qiuworld.com"
      > gsub("\\w+@\\w+\\.[a-zA-Z]{2,4}","gsub_function","abc@qiuworld.com,efd@qiuworld.com")
      [1] "gsub_function,gsub_function"
      </c>
      
      
      正則的使用我們已經看到了,但是讓人看不明白就是字符. \ | ( ) [ { ^ $ * + - ? 這些符號都是什么意思啊?
      下面我就先來仔細講講perl中的正則符號
      <pre lang="c">
      .	# 除了換行以外的任意字符
      ^	# 一行字符串的起始,它並不代表第一個字符,只代表這里開始新的一行字符串。
      $	# 一行字符串的結束,它並不代表最后一個字符(因為換行符並不會被包含進匹配當中),只代表一行字符串到這里結束。
      *	# 零個或者多個之前的字符
      +	# 一個或者多個之前的字符
      ?	# 零個或者一個之前的字符
      
      # 示例部分
      t.e		# t后面跟任意一個非換行字符然后跟字符e
      		# 它可以匹配        the
      		#                 tre
      		#                 tle
      		# 但是不匹配 te
      		#           tale
      ^f		# 一行字符以f起始
      ^ftp	# 一行字符以ftp起始
      e$		# 一行字符以e結尾
      tle$	# 一行字符以tle結尾
      und*	# un跟着零個或者多個d字符
      		# 它會匹配 un
      		#         und
      		#         undd
      		#         unddd (etc)
      .*		# 任意一個無換行的字符串,
      		#  . 匹配任何一個非換行字符
      		#  * 將匹配一個或者多個之前的字符.
      ^$		# 一個空行.
       
      # 在正則中有方括號[],代表可以匹配其中任何一個字符。而^在[]中就有了新的意義,代表“非”, -代表了“之間”
      [qjk]		# q,j,k中任意一個字符
      [^qjk]		# 非q,j,k的任意其它字符
      [a-z]		# a至z中任意一個小寫字符
      [^a-z]		# 非任意一個a至z小寫字符的其它字符(可以是大寫字符)
      [a-zA-Z]	# 任意一個英文字母
      [a-z]+		# 一個或者多個小寫英文字母
       
      # |代表或者 小括號(...)可以把或者的部分括起來。注意小括號可能還有別的用途,但是在R當中先不使用。
       
      jelly|cream	# jelly或者cream
      (eg|le)gs	# eggs或者legs
      (da)+		# da或者dada或者dadada 或者更多個da的重復
       
      # 大括號括住1至2個數字,代表重復次數。
      *	# 零個或者多個之前的字符
      +	# 一個或者多個之前的字符
      ?	# 零個或者一個之前的字符
      {n}	# n個之前的字符
      {n,}	# 大於等於n個之前的字符
      {n,m}	# n至m個之前的字符
       
      # 下面的是一些字符被轉義符\轉義會賦以了一些新的(有可能是約定俗成的)意義
      \n		# 換行符
      \t		# tab
      \w		# 任意字母(包括下划線)或者數字
      		# 等同於[a-zA-Z0-9_]
      \W		# \w的反義.
      		# 等同於[^a-zA-Z0-9_]
      \d		# 任意一個數字,等同於[0-9]
      \D		# \d的反義,等同於[^0-9]
      \s		# 任意一個空格,比如,
      		# space, tab, newline, 等
      \S		# \s的反義,任意一個非空格
      \b		# 單詞的邊界, 不能使用在[]內
      \B		# \b的反義
       
      # 很明顯,對於保留字符$, |, [, ), \, / 等等都需要轉義字符\來轉義表示:
       
      \|		# 豎線
      \[		# \[左方括號 \]右方括號
      \)		# \(左小括號 \)右小括號
      \*		# 星號
      \^		# 開號
      \/		# 反斜杠
      \\		# 斜杠
    

      接下來再講一下POSIX中定義的一些特殊意義的字符(R中預定義的字符組)

      [:alnum:]	# [:alpha:]和[:digit:]的組合
      [:alpha:]	# [:lower:]和[:upper:]的組合
      [:blank:]	# 空格(space, tab),不包括換行符
      [:cntrl:]	# 控制符,在ASCII碼中000~037或者177
      [:digit:]	# 任意數字:0-9
      [:graph:]	# [:alnum:]和[:punct:]的組合
      [:lower:]	# 當前字符集的小寫字母(小寫字母:a-z)
      [:print:]	# 可打印出來的字符,[:graph:]以及空格(即:[:alnum:],[:punct:]和[:space:])
      [:punct:]	# 標點符號,包括:^ ! " # $ % & ' ( ) * + - . / : ; < = > ? @ [ ] \ _ { } ` ~
      [:space:]	# 空格,包括tab, newline, vertical tab, form feed, carriage return, and space
      [:upper:]	# 當前字符集的大寫字母(大寫字母:A-Z)
      [:xdigit:]	# 16進制數 0-9a-fA-F
    

      代表字符組的特殊符號

      代碼	含義說明
      \w	字符串,等價於[:alnum:]
      \W	非字符串,等價於[^[:alnum:]]
      \s	空格字符,等價於[:blank:]
      \S	非空格字符,等價於[^[:blank:]]
      \d	數字,等價於[:digit:]
      \D	非數字,等價於[^[:digit:]]
      \b	Word edge(單詞開頭或結束的位置)
      \B	No Word edge(非單詞開頭或結束的位置)
      \<	Word beginning(單詞開頭的位置)
      \>	Word end(單詞結束的位置)
    

      還有兩個錨點特殊字符

      ^	# 一行字符串的起始,它並不代表第一個字符,只代表這里開始新的一行字符串。
      $	# 一行字符串的結束,它並不代表最后一個字符(因為換行符並不會被包含進匹配當中),只代表一行字符串到這里結束。
      \<	# 單詞左邊界
      \>	# 單詞右邊界
    

      弄清楚了這些正則符號,我們再回過頭來看一點之前的

      pattern <- "^[A-Za-z0-9\\._%+-]+@[A-Za-z0-9\\.-]+\\.[A-Za-z]{2,4}$"
      可以改寫為
      pattern <- "^[\\w\\._%+-]+@[\\w\\.-]+\\.[A-Za-z]{2,4}$"
      或者
      pattern <- "^[[:alnum:]\\._%+-]+@[[:alnum:]\\.-]+\\.[[:alpha:]]{2,4}$"
    

      有人會問了,為什么轉義字符都要寫兩次啊?因為R本身也把 \ 當成轉義字符,所以在寫pattern的時候,就需要使用\\ 來表示轉義字符。還有一種辦法就是設置fixed為TRUE。那么參數中perl是什么意思呢?其實就是指是否使用PCRE的算法,我們來看實例:

      > regexpr("foo|foobar","myfoobar")
      [1] 3
      attr(,"match.length")
      [1] 6
      attr(,"useBytes")
      [1] TRUE
      > regexpr("foo|foobar","myfoobar", perl=TRUE)
      [1] 3
      attr(,"match.length")
      [1] 3
      attr(,"useBytes")
      [1] TRUE
    

參考資料


  1. A-Za-z0-9\._%+- ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM