我有一系列使用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( )
表达式还需要做什么?或者,是否有更好的方法来完全解决这个问题。
答案 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"
答案 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]))
问题将保留为大写字母后的大写字母(请参阅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个小写字母。