如何在句子中添加删除的空格?

时间:2019-05-10 04:00:34

标签: r regex regex-lookarounds

我有以下字符串:

x = "marchTextIWantToDisplayWithSpacesmarch"

我想删除字符串开头的“ march”部分,然后在其余的每个大写字母之前添加一个空格,以产生以下结果:

"Text I Want To Display With Spacesmarch"

要插入空白,我使用了gsub("([a-z]?)([A-Z])", "\\1 \\2", x, perl= T),但是我不知道如何修改模式,以便从返回的字符串中排除第一个“行军”。我正在努力做到这一点,以便能为您提供任何帮助。

4 个答案:

答案 0 :(得分:5)

一种选择是将大写字母捕获为一个组((...)),并在替换中创建一个空格,后跟捕获组的后向引用(\\1

gsub("([A-Z])", " \\1", x)
#[1] "march Text I Want To Display With Spacesmarch"

如果我们需要删除“行军者”

sub("\\b[a-z]\\w+\\s+", "", gsub("([A-Z])", " \\1", x))
[#1] "Text I Want To Display With Spacesmarch"

数据

x <- "marchTextIWantToDisplayWithSpacesmarch"

答案 1 :(得分:4)

否,您无法使用单个gsub来替代您,因为在您的要求之一中,您想从一开始就删除所有小写字母,而您的第二个要求是在每个大写字母前插入一个空格从文本开头删除所有小写字母后,结果字符串的第一个大写字母除外。

在某些情况下我们可以重用一些现有字符来进行条件替换,而在这种情况下是不可能的,则可以通过单个gsub调用来完成。因此,第一步,您可以使用^[a-z]+正则表达式仅从字符串的开头去除所有小写字母,

sub('^[a-z]+', '', "marchTextIWantToDisplayWithSpacesmarch")

把这个留给你,

[1] "TextIWantToDisplayWithSpacesmarch"

接下来,您可以使用此(?<!^)(?=[A-Z])正则表达式在除第一个大写字母之前的每个大写字母之前插入一个空格,因为您可能不希望在句子前添加多余的空格。但是您可以将两者结合起来并写成这样,

gsub('(?<!^)(?=[A-Z])', ' ', sub('^[a-z]+', '', "marchTextIWantToDisplayWithSpacesmarch"), perl=TRUE)

这将为您提供所需的字符串,

[1] "Text I Want To Display With Spacesmarch"

编辑: (?<!^)(?=[A-Z])模式的说明

首先,让我们采用(?=[A-Z])模式,

See the pink markers in this demo

如您所见,在演示中,每个大写字母前都有一个粉红色标记,这是将插入空格的位置。但是我们不希望在第一个字母之前插入空格,因为这是不需要的。因此,我们需要在正则表达式中使用一个条件,该条件不会选择出现在字符串开头的第一个大写字母。为此,我们需要在(?<!^)之后使用否定的外观,这表示请勿选择以字符串开头开头的位置,因此,(?<!^)有助于丢弃在字符串开头的大写字母。

See this demo where the pink marker is gone from the very first uppercase letter

希望这可以阐明如何选择其他大写字母,而不是首字母。让我知道您是否还有任何疑问。

答案 2 :(得分:3)

您可以对gsub使用单个正则表达式调用,并与trimws结合使用以修剪结果字符串:

trimws(gsub("^\\p{Ll}+|(?<=.)(?=\\p{Lu})", " ", x, perl=TRUE))
## => [1] "Text I Want To Display With Spacesmarch"

它还支持所有Unicode小写(\p{Ll})和大写(\p{Lu})字母。

请参见R demo onlineregex demo

详细信息

  • ^\\p{Ll}+-字符串开头为1个或多个小写字母
  • |-或
  • (?<=.)(?=\\p{Lu})-除换行符和大写字母之外的任何字符之间的任何位置。

这里是一个替代品,它只需使用一些gsubfn逻辑即可调用ifelse正则表达式:

> gsubfn("^\\p{Ll}*(\\p{L})|(?<=.)(?=\\p{Lu})", function(n) ifelse(nchar(n)>0,n," "), x, perl=TRUE,backref=-1) 
[1] "Text I Want To Display With Spacesmarch"

这里,^\\p{Ll}*(\\p{L})部分匹配0+小写字母,并将下一个大写字母捕获到组1中,这将通过将n参数传递给匿名函数来进行访问。如果n的长度不为零,则此替代项匹配,我们需要用该值替换。否则,我们用空格代替。

答案 3 :(得分:1)

因为这被标记为perl,所以我要2美分:

您可以将sub()gsub()内部的替换链接在一起吗?在较新的perl版本中,可以将/r选项添加到s///替换中,以便可以“无损地”返回匹配的字符串,然后再次进行匹配。这样就可以在不掌握高级语法(例如

)的情况下进行恶意的匹配/替换/重新匹配
perl -E '
  say "marchTextIWantToDisplayWithSpacesmarch" =~
  s/\Amarch//r =~ s/([[:upper:]])/ $1/gr  =~ s/\A\s//r;'

输出

Text I Want To Display With Spacesmarch

这似乎是@ pushpesh-kumar-rajwanshi和@akrun通过将gsub包装在sub()内来完成的,反之亦然。总的来说,我不认为perl = T捕获了perl正则表达式的全部惊人的疯狂功能,但gsub/sub必须在向量上快速运行,不是吗?