2016-11-23 34 views
14

我想用數學比較來分割表達式,例如,在數學比較中的分割字符向量R

unlist(strsplit("var<3", "(?=[=<>])", perl = TRUE)) 
unlist(strsplit("var==5", "(?=[=<>])", perl = TRUE)) 
unlist(strsplit("var>2", "(?=[=<>])", perl = TRUE)) 

的結果是:

[1] "var" "<" "3" 
[1] "var" "=" "=" "5" 
[1] "var" ">" "2" 

對於上面的第二個例子,我想獲得[1] "var" "==" "5",所以這兩個=應返回作爲一個單一的元素。我如何需要改變我的正則表達式來實現這一點? (我已經嘗試過分組和量詞爲「==」,但是毫無效果 - 正則表達式是不是我的朋友...)

+0

你只想限制爲'''','<'和'=='嗎? –

+0

@Wiktor,是的,我只想限制>,<和==的分割。也許也是!=。 – Daniel

+1

順便說一句,你可以使用'sub(「(。*?)([= <>]。)(。*)」,「\\ 2」,「var == 55」,perl = TRUE)或類似的東西。你也可以用它來分割'strsplit(sub(「(。*?)([= <>]。)(。*)」,「\\ 1 \\ 2 \\ 3」,「var == 55」 ,perl = TRUE),「」)'但是Wiktors解決方案可能更好 –

回答

9

你可以使用一個PCRE正則表達式來個匹配子串,你需要:

==|[<>]|(?:(?!==)[^<>])+ 

也支持!=,修改爲

[!=]=|[<>]|(?:(?![=!]=)[^<>])+ 

regex demo

詳細

  • == - 2個=跡象
  • | - 或
  • [<>] - 一個<>
  • | - 或
  • (?:(?!==)[^<>])+ - 其它1個或多個字符比<>[^<>])不開始== char序列(回火貪婪標記)。

注意:這是通過增加更多的選擇和調整的磨礪貪婪令牌容易擴展。

R test

> text <- "Text1==text2<text3><More here" 
> res <- regmatches(text, gregexpr("==|[<>]|(?:(?!==)[^<>])+", text, perl=TRUE)) 
> res 
[[1]] 
[1] "Text1"  "=="  "text2"  "<"   "text3"  ">"   
[7] "<"   "More here" 
+0

我把'([a-zA-Z0-9 _] +)([^ a-zA-Z0-9 _] +)([a-zA-Z0-9 _] +)'作爲正則表達式應用於操作符chars不會出現在他們的任何一方。 – Tensibai

+1

@Tensibai:你的意思是你必須檢查這些操作員的雙方是否有字符?您可以使用['「\\ b(?:[!=] = | [<>])\\ b」'](https://regex101.com/r/0khTUq/1) –

+1

要使regmatches返回3捕獲組我認爲指定它們會更好,使用perl像\ w會更好,但我覺得這樣更容易理解。一世。e:'regmatches(tests,regexec(「([a-zA-Z0-9 _] +)([^ a-zA-Z0-9 _] +)([a-zA-Z0-9 _] +)) ))'在哪裏測試是一個向量會給每個部分在它自己的捕獲組的初始。 (這只是一個替代) – Tensibai

5

使用單詞邊界(\\b)並指定環視兩個可能性:

unlist(strsplit("var==5", "(?=(\\b[^a-zA-Z0-9])|(\\b[a-zA-Z0-9]\\b))", perl = TRUE)) 
[1] "var" "==" "5" 

unlist(strsplit("var<3", "(?=(\\b[^a-zA-Z0-9])|(\\b[a-zA-Z0-9]\\b))", perl = TRUE)) 
[1] "var" "<" "3" 
unlist(strsplit("var>2", "(?=(\\b[^a-zA-Z0-9])|(\\b[a-zA-Z0-9]\\b))", perl = TRUE)) 
[1] "var" ">" "2" 

說明:

拆分在「字」,結束時,之後,有或者是一個非字母數字字符\\b[^a-zA-Z0-9]或它是「詞」和結束時,之後,有一個字母數字字符。

編輯:

實際上上面的代碼將具有意想不到的結果,如果在端部的數量爲10以上。
另一種選擇是使用lookbehind和分裂時,前,有要麼非alphanum字符後跟一個字邊緣,或一個alphanum字符後跟一個字邊緣:

strsplit("var<20", "(?<=(([^a-zA-Z0-9]\\b)|([a-zA-Z0-9]\\b)))", perl = TRUE)[[1]] 
#[1] "var" "<" "20" 
strsplit("var==20", "(?<=(([^a-zA-Z0-9]\\b)|([a-zA-Z0-9]\\b)))", perl = TRUE)[[1]] 
#[1] "var" "==" "20" 
strsplit("var!=5", "(?<=(([^a-zA-Z0-9]\\b)|([a-zA-Z0-9]\\b)))", perl = TRUE)[[1]] 
#[1] "var" "!=" "5" 

EDIT2:

共竊取@Tensibai的方式來定義alphanum(+下劃線)/非alphanum字符,上述regex可以簡化到:"(?<=((\\W\\b)|(\\w\\b)))"

6

從我的意見想法擴大,只是格式:

tests=c("var==5","var<3","var.name>5") 
regmatches(tests,regexec("([a-zA-Z0-9_.]+)(\\W+)([a-zA-Z0-9_.]+)",tests)) 

\w[a-zA-Z0-9_]\W它的對面[^a-zA-Z0-9_],我擴大之後的評論,包括。在字符類中,因爲R不支持基本正則表達式中的字符類中的\ w(需要使用perl = TRUE)。

因此,正則表達式搜索\ w和。,然後至少1不在\ w(匹配運算符),然後至少1 \ w和點。

每一步都被捕獲,這給予:

[[1]] 
[1] "var==5" "var" "=="  "5"  

[[2]] 
[1] "var<3" "var" "<"  "3"  

[[3]] 
[1] "var.name>5" "var.name" ">"   "5"  

你可以捕捉每個組之間添加*如果你的項目可有周圍操作空間,如果不是經營者捕獲會得到他們。

+1

不錯的一個(我會採取它,你不介意我用你來簡化我的正則表達式);-p – Cath

+0

謝謝你,很好和短的解決方案 - 但是,這一個不使用帶點的變量名稱,例如'regmatches( 「var.name == 5」,regexec( 「(\\ W +)(\\ W +)(\\ W +)」, 「var.name == 5」))'。我試過類似regmatches(「var.name == 5」,regexec(「(\\ w | [。] +)(\\ W +)(\\ w +)」,「var.name == 5」)) )',但那個人吃了字符向量的「==」部分。 – Daniel

+0

@Daniel糾正了,只是使用一個字符類將'.'添加到允許的字符 – Tensibai