2016-02-21 22 views
1

我有對應於一個低於生成的矢量VECA工作:選擇數字

vecA <- c("[ 0, 10)", "[ 10, 20)", "[ 20, 30)", "[ 50, 60)", "[ 90,100]") 

我想在vecB去除特殊字符到達,插入連字符,如在樣品中下方產生:

vecB <- c("0 - 10", "10 - 20", "20 - 30", "50 - 60", "90 - 100") 

問題

我以前做的gsub語法,即幾乎作品:

vecB <- gsub(pattern = 
       "^(\\[{1})([[:blank:]]*)(\\d{1,2})([,])(.*)(\\d{2,3})([[:punct:]])$", 
          x = vecA, replacement = "\\3 - \\6") 

唯一的問題是與錯誤地轉化爲90 - 0090 - 100因爲它應該是(regex101)值[ 90,100]

+0

我不知道你是否對你的正則表達式錯誤感興趣。提示:'(。*)'。 –

回答

2

我們可以使用捕獲組,即在(..)之內獲取數字部分並刪除所有其他數字部分,即非數字部分(\\D+)。

在下面的模式,我們匹配一個或多個非數字元素(\\D+ - 它包括[和空白以下的話),然後捕獲的一個或多個數字((\\d+)),隨後通過匹配所述一個或多個非數字(\\D+ - 匹配,和後面的空格),第二個捕獲組數字(\\d+),然後是.*,即它匹配字符串的其餘部分直到其結尾。在替換中,我們指定反向引用(\\1),後跟空格,然後是-和第二個反向引用('\ 2`)。

sub('\\D+(\\d+)\\D+(\\d+).*', '\\1 - \\2', vecA) 
#[1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

編輯:基於從@WiktorStribiżew


或者我們可以使用從library(stringr)str_extract提取數字,然後paste一起

library(stringr) 
sapply(str_extract_all(vecA, '[0-9]+'), paste, collapse=' - ') 
#[1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 
+0

我看到我太過於複雜。 – Konrad

+1

我不會將'。*'描述爲*零個或多個字符*。在R TRE正則表達式中的模式結尾處,它表示*將字符串的其餘部分與其結尾*進行匹配。 –

2

1)子評論/ gsub這可以分解爲兩個簡單的sub/gsub調用。內部gsub用空字符串替換不是數字或逗號的任何內容,並且外部將逗號轉換爲空格減號空格。

sub(",", " - ", gsub("[^0-9,]", "", vecA)) 
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

2)一個子要與一個sub做到這一點:

sub("^\\D*(\\d+)\\D*(\\d+)\\D*$", "\\1 - \\2", vecA) 
## "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

3)串/讀取。表這其中不使用子或GSUB或任何正則表達式:

with(read.table(text = substring(vecA, 2, nchar(vecA)-1), sep = ","), paste(V1, "-", V2)) 
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

3a)的的這種變化(3)是稍短:

with(read.table(text = gsub("\\D", " ", vecA)), paste(V1, "-", V2)) 
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

4)gsubfn該提取物捕獲組和執行指示paste

library(gsubfn) 
strapply(vecA, "(\\d+)\\D*(\\d+)", ~ paste(x, "-", y), simplify = c) 
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

4A)(4),其使用stapplyc而非strapply的變異:

library(gsubfn) 
sapply(strapplyc(vecA, "\\d+"), paste, collapse = " - ") 
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

4B)的變化(4),其使用gsubfn而非strapply

library(gsubfn) 
gsubfn("\\D+", ~ if (grepl(",", x)) " - " else "", vecA) 
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 

5) strsplit這是另一種不使用sub或gsub的解決方案:

f <- function(x) { 
    paste0(ifelse(x == ",", " - ", ifelse(x %in% 0:9, x, "")), collapse = "") 
} 
sapply(strsplit(vecA, ""), f) 
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100" 
+2

沒有注意到其他人已經給出了幾乎與(2)相同的答案。 –

2

提醒我,我正在很好地解決標籤間隔相同的問題。這是我的結果,無視這裏沒有正則表達式:

library(dplyr) 

# 1-9 by one, up to 75 by 5, up to 300 by 50, rest by 100 
c(0:9, 
    seq(14, 50, by=5), 
    seq(59, 100, by=10), 
    seq(149, 300, by=50), 
    seq(400, 1000, by=100)) -> 
    breaks 

# create nice labels for the intervals 
# assuming integral numbers will be cut by the breaks (hence the `l + 1`) 
data.frame(l = breaks[1:length(breaks) - 1], 
      r = breaks[2:length(breaks)]) %>% 
       mutate(diff = r - l, 
         lab = ifelse(diff > 1, 
            paste0(l + 1, " - ", r), 
            as.character(r))) -> 
    labs 

# and cut() the data in `pos` colum getting directly the factors with 
# nice names 
d %>% mutate(bin=cut(pos, breaks, labels=labs$lab))