在R中截取一个字符串的末尾,该字符串可能包含零个或多个特定字符。

8

我有以下数据:

temp<-c("AIR BAGS:FRONTAL" ,"SERVICE BRAKES HYDRAULIC:ANTILOCK",
    "PARKING BRAKE:CONVENTIONAL",
    "SEATS:FRONT ASSEMBLY:POWER ADJUST",
    "POWER TRAIN:AUTOMATIC TRANSMISSION",
    "SUSPENSION",
    "ENGINE AND ENGINE COOLING:ENGINE",
    "SERVICE BRAKES HYDRAULIC:ANTILOCK",
    "SUSPENSION:FRONT",
    "ENGINE AND ENGINE COOLING:ENGINE",
    "VISIBILITY:WINDSHIELD WIPER/WASHER:LINKAGES")

我希望创建一个新的向量,仅保留在存在“:”的情况下第一个“:”之前的文本,并在不存在“:”时保留整个单词。

我尝试使用:

temp=data.frame(matrix(unlist(str_split(temp,pattern=":",n=2)), 
+                        ncol=2, byrow=TRUE))

但在没有“:”的情况下,这种方法无法工作。

我知道这个问题与R中截断特定字符的字符串非常相似,该问题使用了:

sub("^[^.]*", "", x)

但是我对正则表达式不是很熟悉,一直在努力尝试将该示例反转以仅保留字符串的开头。

5个回答

16

你可以使用简单的正则表达式解决这个问题:

sub("(.*?):.*", "\\1", x)
 [1] "AIR BAGS"                  "SERVICE BRAKES HYDRAULIC"  "PARKING BRAKE"             "SEATS"                    
 [5] "POWER TRAIN"               "SUSPENSION"                "ENGINE AND ENGINE COOLING" "SERVICE BRAKES HYDRAULIC" 
 [9] "SUSPENSION"                "ENGINE AND ENGINE COOLING" "VISIBILITY"     
正则表达式的工作原理:
- "(.*?):.*" 查找一组重复出现的任意字符.*,但通过添加“?”来使其变得非贪婪。这应该后跟一个冒号和任意字符(重复)。 - 将整个字符串替换为括号内找到的位 - "\\1"。
需要了解的是,默认情况下,任何正则表达式匹配都是贪婪的。通过修改它变成非贪婪模式,第一个模式匹配不可以包含冒号,因为括号后的第一个字符是冒号。冒号后面的正则表达式回到了默认状态,即贪婪模式。

谢谢你!以及正则表达式的解释。 - Tony M.

9
另一种方法是寻找第一个“:”并用空格替换它及其后面的任何内容:
yy <- sub(":.*$", "", yy )

如果未找到“:”,则不会被替换,将返回原始字符串的全部内容。如果存在“:”,则匹配第一个冒号及其后面的所有字符,然后用空字符串("")替换它,即删除该部分并将其之前的所有内容保留下来。

3

假设你的数据是以字符向量的形式存储,以下代码是否可行:

x <- c('foobar','foo:bar','foo1:bar1 foo:bar','foo bar')
> sapply(str_split(x,":"),'[',1)
[1] "foobar"  "foo"     "foo1"    "foo bar"

这是我马上想到的答案。就速度而言,您认为这与正则表达式解决方案相比如何? - Dason
@Dason 我也是这么想的,因为我还没有完全掌握正则表达式,但我对速度并不抱有太高的期望。 - joran

3

抱歉以回答的形式添加此内容。针对所需时间的回应:

> yy<-rep("foo1:bar1",times=100000)
> system.time(yy1<-sapply(strsplit(yy,":"),'[',1))
   user  system elapsed 
   0.26    0.00    0.27 
> 
> system.time(yy2<-sub("(.*?):.*", "\\1", yy))
   user  system elapsed 
    0.1     0.0     0.1 
> 
> system.time(yy3 <- sub(":.*$", "", yy ))
   user  system elapsed 
   0.08    0.00    0.07 
> 
> system.time(yy4<-gsub("([^:]*).*","\\1",yy))
   user  system elapsed 
   0.09    0.00    0.09 

正则表达式大致相当于字符串分割,但后者需要更长的时间。

有用的扩展注释。我发现最简单的正则表达式,@GregSnow的,也是最快的,这让我感到振奋。其他两个正则表达式解决方案对于它们作为一种启动“否定”的字符类的说明以及使用未修改的“?”来抑制贪婪行为的解释非常有启发性。 - IRTFM

1

在这种情况下

yy<-c("AIR BAGS:FRONTAL",
"SERVICE BRAKES HYDRAULIC:ANTILOCK",
"PARKING BRAKE:CONVENTIONAL",
"SEATS:FRONT ASSEMBLY:POWER ADJUST",
"POWER TRAIN:AUTOMATIC TRANSMISSION",
"SUSPENSION",
"ENGINE AND ENGINE COOLING:ENGINE",
"SERVICE BRAKES HYDRAULIC:ANTILOCK",
"SUSPENSION:FRONT",
"ENGINE AND ENGINE COOLING:ENGINE",
"VISIBILITY:WINDSHIELD WIPER/WASHER:LINKAGES")
yy<-gsub("([^:]*).*","\\1",yy)
yy

可能适合您


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接