在R

时间:2016-04-21 18:57:17

标签: regex r

我有一系列使用PascalCase的字符串。

"BobDylan"
"MikhailGorbachev" 
"HelpfulStackOverflowPeople"

我想在R中使用一个函数,在每个单词之间放置空格。我用perl像正则表达式和gsub( )函数实现了这一点。基本上,我在每个大写字母之前放置一个空格,而不是字符串的第一个字母。

gsub("(?!^)(?=[A-Z])", " ","BobDylan",perl=TRUE)
[1] "Bob Dylan"

但是,我的列表中的某些单词可能包含大写的缩写,我不希望用空格分隔。

"BobDylanUSA"
"MikhailGorbachevUSSR" 
"HelpfulStackOverflowPeople"

从之前应用相同的语法将在每个大写字母之间创建空格。

gsub("(?!^)(?=[A-Z])", " ","MikhailGorbachevUSSR",perl=TRUE)
[1] "Mikhail Gorbachev U S S R"

但是,我希望缩写保持不变。所需的输出如下所示。

[1] "Bob Dylan USA"
[1] "Mikhail Gorbachev USSR"
[1] "Helpful Stack Overflow People"

我的gsub( )表达式还需要做什么?或者,是否有更好的方法来完全解决这个问题。

3 个答案:

答案 0 :(得分:2)

我刚刚为此目的开发了蛇形包装,并想提升一点;-)希望这有帮助!

install.packages("snakecase")
library(snakecase)

string <- c("BobDylanUSA",
            "MikhailGorbachevUSSR",
            "HelpfulStackOverflowPeople",
            "IAmATallDrinkOfWater")

to_any_case(string, case = "parsed", sep_out = " ")
#> [1] "Bob Dylan USA"                 "Mikhail Gorbachev USSR"       
#> [3] "Helpful Stack Overflow People" "I Am A Tall Drink Of Water"  

https://github.com/Tazinho/snakecase

答案 1 :(得分:1)

x <- c("BobDylanUSA",
       "MikhailGorbachevUSSR",
       "HelpfulStackOverflowPeople")

gsub('[a-z]\\K(?=[A-Z])', ' ', x, perl = TRUE)

# [1] "Bob Dylan USA"                 "Mikhail Gorbachev USSR"       
# [3] "Helpful Stack Overflow People"

或者

gsub('(?<=[a-z])(?=[A-Z])', ' ', x, perl = TRUE)

# [1] "Bob Dylan USA"                 "Mikhail Gorbachev USSR"       
# [3] "Helpful Stack Overflow People"

或者这个人也会分割像I或A这样的单字母单词

x <- c("BobDylanUSA",
       "MikhailGorbachevUSSR",
       "HelpfulStackOverflowPeople",
       "IAmATallDrinkOfWater")

gsub('(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])', ' ', x, perl = TRUE)

# [1] "Bob Dylan USA"                 "Mikhail Gorbachev USSR"       
# [3] "Helpful Stack Overflow People" "I Am A Tall Drink Of Water" 

答案 2 :(得分:1)

您可以稍微修改自己的正则表达式:将前瞻转换为捕获组,并在+字符类之后添加[A-Z]量词,使其匹配1个以上的字符:

> v <- c("BobDylan","MikhailGorbachev","HelpfulStackOverflowPeople","BobDylanUSA","MikhailGorbachevUSSR","HelpfulStackOverflowPeople")
> gsub("(?<!^|\\s)([A-Z]+)", " \\1", v, perl=T)
[1] "Bob Dylan"                     "Mikhail Gorbachev"            
[3] "Helpful Stack Overflow People" "Bob Dylan USA"                
[5] "Mikhail Gorbachev USSR"        "Helpful Stack Overflow People"

它仍然是一个PCRE正则表达式,因为你不想在字符串的开头添加一个空格(这里有一个lookbehind (?<!^),只有在大写字母之前没有空格。

请参阅此regex demo

非PCRE替代

如果您想尝试使用 TRE (非PCRE)正则表达式

> gsub("(\\S)([A-Z]+)", "\\1 \\2", v)
[1] "Bob Dylan"                     "Mikhail Gorbachev"            
[3] "Helpful Stack Overflow People" "Bob Dylan USA"                
[5] "Mikhail Gorbachev USSR"        "Helpful Stack Overflow People"

这是 another regex demo

此处,模式匹配并捕获任何一个非空格字符(\\S),后跟1 +大写ASCII字母捕获到第2组(请参阅([A-Z]+)),然后我们使用\\1替换模式中的\\2 numbered backreferences以在这些捕获的子值之间添加空格。

我尝试拆分单字大写字母

由于单字母单词只能匹配一次,我们需要能够匹配它们之前和之后的位置,这需要使用 lookarounds ,因为只有lookarounds允许“重叠”匹配通过对(lookbehinds)之前和之后(lookaheads)的文本执行所谓的零宽度断言检查当前位置。因此,只有PCRE正则表达式可以处理

那就是说,任何一种解决方案都会产生相同的结果:

(?|([a-z])(?=[A-Z])|([A-Z]+)(?=[A-Z][a-z]))

this regex demo

问题将保留为大写字母后的大写字母(请参阅Mail Sent To USAA Day Ago)。您需要进行字典检查。

> v <- c("BobDylan","MikhailGorbachev","BobDylanUSA","MikhailGorbachevUSSR","HelpfulStackOverflowPeople","IAmATallDrinkOfWater","MailSentToUSAADayAgo")
> gsub("(?|([a-z])(?=[A-Z])|([A-Z]+)(?=[A-Z][a-z]))", "\\1 ", v, perl=T)
[1] "Bob Dylan"                     "Mikhail Gorbachev"            
[3] "Bob Dylan USA"                 "Mikhail Gorbachev USSR"       
[5] "Helpful Stack Overflow People" "I Am A Tall Drink Of Water"   
[7] "Mail Sent To USAA Day Ago"    

由于branch reset(?|...|...)),模式将匹配并捕获模式内的捕获组。捕获的文本通过反向引用插回,然后添加一个空格。

  • ([a-z])(?=[A-Z]) - 在小写字母后面跟一个大写字母
  • ([A-Z]+)(?=[A-Z][a-z]) - 在1个大写字母后跟1个大写字母,然后是1个小写字母。