提取可能多次出现或根本不出现的字符串元素

时间:2014-06-19 21:57:46

标签: r substring regex-lookarounds strsplit

从URL的字符向量开始。目标是最终只使用公司名称,这意味着下面的示例中只有"test""example""sample"的列。

urls <- c("http://grand.test.com/", "https://example.com/", 
          "http://.big.time.sample.com/")

删除".com"及其后跟随的内容并保留第一部分:

urls <- sapply(strsplit(urls, split="(?<=.)(?=\\.com)", perl=T), "[", 1) 

urls
# [1] "http://grand.test"    "https://example"      "http://.big.time.sample"

我的下一步是通过链接http://来删除https://gsub()部分:

urls <- gsub("^http://", "",  gsub("^https://", "", urls))

urls
# [1] "grand.test"       "example"          ".big.time.sample"

但这是我需要帮助的地方。如何在第一个和第三个网址字符串中处理公司名称之前的多个句点(点)?例如,下面的调用返回第二个字符串的NA,因为"example"字符串没有剩余句点。或者,如果我只保留第一部分,我就会丢失公司名称。

urls  <- sapply(strsplit(urls, split = "\\."), "[", 2)
urls
# [1] "test" NA     "big"

urls  <- sapply(strsplit(urls, split = "\\."), "[", 1)
urls
# [1] "grand"   "example" ""  

也许ifelse()来电会计算剩余时段的数量,如果有多个时段,则仅使用strsplit?另请注意,公司名称前可能有两个或更多个期间。我不知道如何做外观,这可能解决我的问题。但这并没有

strsplit(urls, split="(?=\\.)", perl=T)

感谢您提出任何建议。

7 个答案:

答案 0 :(得分:3)

我认为应该更简单,但这有效:

 sub('.*[.]','',sub('https?:[/]+[.]?(.*)[.]com[/]','\\1',urls))
 [1] "test"    "example" "sample" 

你在哪里“网址”是你的网址。

答案 1 :(得分:3)

我认为有一种方法可以在&#39; .com`之前提取这个词,但也许会给出一个想法

sub(".com", "", regmatches(urls, gregexpr("(\\w+).com", urls)))

答案 2 :(得分:3)

这种方法可能比其他方法更容易理解和概括:

pat = "(.*?)(\\w+)(\\.com.*)"
gsub(pat, "\\2", urls)

它的工作原理是将每个字符串分成三个捕获组,这三个捕获组一起匹配整个字符串,然后在仅捕获组(2)中替换为您想要的那个。

pat = "(.*?)(\\w+)(\\.com.*)"
#        ^    ^       ^
#        |    |       |
#       (1)  (2)     (3)  

修改(添加?修饰符的说明)

请注意,捕获组(1)需要包含“ungreedy”或“minimal”量词?also sometimes called "lazy" or "reluctant")。它基本上告诉正则表达式引擎匹配尽可能多的字符...而不用掉任何可能成为以下捕获组(2)的一部分的字符。

没有尾随?,重复量词默认为贪心;在这种情况下,一个贪婪的捕获组(.*),因为它匹配任意数量的任何类型的字符,将“吃掉”字符串中的所有字符,而对于其他两个捕获组则根本不留下任何字符 - 不是我们想要的行为!

答案 3 :(得分:2)

使用strsplit也值得一试:

sapply(strsplit(urls,"/|\\."),function(x) tail(x,2)[1])
#[1] "test"    "example" "sample"

答案 4 :(得分:2)

这是一个很好的例子。有用的答案和一些解释很快就产生了。

回答我自己的问题并没有描述我在做什么。我想感谢贡献者,回馈一些可以帮助其他人看看这个问题,并解释为什么我选择了一个答案。评论似乎不对,也不够长。

下面将我的每个答案与我的(谦虚,并且很乐意纠正)解释,其中几个包含来自答复者的解释。仔细阅读答案教会了我很多,并帮助我选择了一个首选答案。其他人使用非基本R函数,一个创建的函数,可能很好但不是很容易获得。我喜欢第二个答案,因为它只使用了子功能,但我将桂冠花圈送到了第五个,因为它优雅地使用了我非常高兴学习的两种技术。谢谢大家。

ANS 1

sub(".com", "", regmatches(urls, gregexpr("(\\w+).com", urls)))

gregexpr“w+”之前使用特殊字词“.com”找到任何一个或多个单词,并返回一个包含length和usebytes的列表

regmatches获取gregexpr找到的内容并返回已识别的字符串

sub从每个字符串中删除第一个“.com”[我不知道为什么gsub不起作用,但是当你只想要第一个实例时,全局子可能存在风险]

ANS 2

sub('.*[.]','', sub('https?:[/]+[.]?(.*)[.]com[/]','\\1',urls))

内部子句通过问号特殊字符?处理“http:”和“https:”,这允许“s”是可选的

内部子函数然后处理一个或多个“/”,其中一个字符类只包含一个正斜杠但由“+”扩展,即在http://

中两次

内部子正则表达式向右读取的下一部分包括任意数量的字符作为“[.]?

的可选字符

接下来,“com”之前的句号放在括号中而不是转义它

然后“com”接着是正斜杠[我不确定我理解那部分]

“’\\1’仅保留子函数提取的第一部分

所有上述内容都会返回:

[1] "grand.test"      "example"         "big.time.sample"

最左边的子函数获取内部子函数的结果,并删除括号内的“.*”之前的所有字符

ANS 3

sapply(strsplit(urls, "/|\\."), function(x) tail(x,2)[1])

首先,strsplit使用垂直管道将每个字符串分隔正斜杠或句点产生一个列表

[[1]]
[1] "http:" ""      "grand" "test"  "com"  

[[2]]
[1] "https:"  ""        "example" "com"    

[[3]]
[1] "http:"  ""       ""       "big"    "time"   "sample" "com"

接下来,一个匿名函数使用tail函数找到每个字符串中的最后两个元素,并选择第一个元素,从而整齐地消除每个“.com”

使用sapply函数包装这两个步骤将匿名函数的操作向量化为所有三个字符串

ANS 4

library(stringr)
word(basename(urls), start = -2, sep = "\\.")

basename函数返回

[1] "grand.test.com"       "example.com"          ".big.time.sample.com"

从帮助到basename()我们了解到“basename删除了所有路径,包括最后一个路径分隔符(如果有的话)”这整齐地删除了http://和https://元素。

然后,word()函数使用负运算符(start = -2)从末尾获取第二个“单词”,假设分隔符为。 (期间)(sep =“\。”)。

ANS 5

pat = "(.*?)(\\w+)(\\.com.*)"
gsub(pat, "\\2", urls)

分配给对象“pat”的正则表达式将每个字符串分成三个捕获组,这些捕获组一起匹配整个字符串

使用gsub函数,搜索“pat”字符串,它将仅替换为捕获组(2),即所需部分。

请注意两种技术:使用表达式创建对象,然后在正则表达式中使用它。此方法有助于保持代码更清晰,更易于阅读 - 如gsub调用行所示。其次,请注意捕获组的使用,捕获组是括在括号中的正则表达式的组成部分。它们可以在以后使用,就像本例中的“'\ 2'”

一样
pat = "(.*?)(\\w+)(\\.com.*)"
#        ^    ^       ^
#        |    |       |
#       (1)  (2)     (3)  

ANS 6

regcapturedmatches(urls, regexpr("([^.\\/]+)\\.com", urls, perl=T))

这可能是一个很好的解决方案,但它依赖的函数regcapturematches不在基础R或其他包中,例如qdapstringi或{{1} }

先生。 Flick提出了一个很好的观点,“如果你只需要一个简单的向量作为返回值,你就可以取消列出()结果。”

他解释说“模式的想法是在”.com“之前抓住所有不是点或”/“的东西。”这是括号中的表达式,+符号表示它可以是多。

Perl = T似乎是所有正则表达式的好参数

答案 5 :(得分:1)

您可以使用stringr::word()以及basename()

使用网址时,

basename()非常方便。

> library(stringr)
> word(basename(urls), start = -2, sep = "\\.")
# [1] "test"    "example" "sample"  

basename(urls)给出了

[1] "grand.test.com"       "example.com"          ".big.time.sample.com"

然后,在word()函数中,我们从结尾(start = -2)获取第二个单词,假设分隔符为.sep = "\\.")。

答案 6 :(得分:1)

因为你从来没有足够的正则表达式选项,所以这里使用regcapturedmatches.R函数

regcapturedmatches(urls, regexpr("([^.\\/]+)\\.com", urls, perl=T))

如果您只需要一个简单的向量作为返回值,则可以unlist()结果。模式的想法是抓住所有不是一个点或一个&#34; /&#34;紧接着&#34; .com&#34;。