如何修剪前导和尾随空格?


360

我在data.frame中的前导和尾随空白时遇到了一些麻烦。例如,我想看看在特定rowdata.frame基础上有一定的条件:

> myDummy[myDummy$country == c("Austria"),c(1,2,3:7,19)] 

[1] codeHelper     country        dummyLI    dummyLMI       dummyUMI       
[6] dummyHInonOECD dummyHIOECD    dummyOECD      
<0 rows> (or 0-length row.names)

我想知道为什么我没有得到预期的产出,因为我的国家显然存在奥地利这个国家data.frame。在查看了我的代码历史记录并尝试找出出了什么问题之后,我尝试了:

> myDummy[myDummy$country == c("Austria "),c(1,2,3:7,19)]
   codeHelper  country dummyLI dummyLMI dummyUMI dummyHInonOECD dummyHIOECD
18        AUT Austria        0        0        0              0           1
   dummyOECD
18         1

我在命令中所做的更改只是在奥地利之后增加了一个空白。

显然还会出现更多令人讨厌的问题。例如,当我想基于“国家/地区”列合并两个框架时。一个data.frame使用"Austria "而另一帧使用"Austria"。匹配无效。

  1. 有没有一种很好的方法可以在屏幕上“显示”空白,从而使我意识到问题所在?
  2. 我可以删除R中的前导和尾随空格吗?

到目前为止,我曾经写过一个简单的Perl脚本来删除空格,但是如果我能以某种方式在R中完成它会很好。


1
我刚刚看到它也sub()使用了Perl表示法。对于那个很抱歉。我将尝试使用该功能。但是对于我的第一个问题,我还没有解决方案。
mropa'2

4
正如hadley指出的那样,此正则表达式“ ^ \\ s + | \\ s + $”将标识前导和尾随空格。因此x <-gsub(“ ^ \\ s + | \\ s + $”,“”,x)R的许多读取函数都具有以下选项:strip.white = FALSE
Jay

Answers:


456

最好的方法可能是在读取数据文件时处理尾随空格。如果使用read.csvread.table可以设置参数strip.white=TRUE

如果以后要清理字符串,可以使用以下功能之一:

# returns string w/o leading whitespace
trim.leading <- function (x)  sub("^\\s+", "", x)

# returns string w/o trailing whitespace
trim.trailing <- function (x) sub("\\s+$", "", x)

# returns string w/o leading or trailing whitespace
trim <- function (x) gsub("^\\s+|\\s+$", "", x)

在以下位置使用这些功能之一myDummy$country

 myDummy$country <- trim(myDummy$country)

要“显示”空白,您可以使用:

 paste(myDummy$country)

它将显示带引号(“)括起来的字符串,使空格更容易发现。


7
正如hadley指出的那样,此正则表达式“ ^ \\ s + | \\ s + $”将标识前导和尾随空格。因此x <-gsub(“ ^ \\ s + | \\ s + $”,“”,x)R的许多读取函数都具有以下选项:strip.white = FALSE
Jay 2010年

50
另请参阅str_trimstringr包中。
Richie Cotton

1
再加上一个“现在已修剪功能供将来使用”-谢谢!
克里斯·比利

4
不幸的是,strip.white = TRUE仅适用于未引用的字符串。
罗德里戈

2
在R 3.2.0中,有一种更简单的方法来修剪空白。查看下一个答案!
Alex

519

从R 3.2.0开始,引入了一个新功能来删除前导/尾随空格:

trimws()

请参阅:http//stat.ethz.ch/R-manual/R-patched/library/base/html/trimws.html


2
这取决于最佳答案的定义。知道这个答案很高兴(+1),但是在快速测试中,它的速度不如那里的一些替代方法快。
A5C1D2H2I1M1N2O1R2T1

尽管\n处于覆盖字符类中,但它似乎不适用于多行字符串。trimws("SELECT\n blah\n FROM foo;")仍然包含换行符。
2015年

6
@Jubbles这是预期的行为。在传递给修剪的字符串中,没有前导或尾随空格。如果要从字符串的每一行中删除开头和结尾的空格,则必须首先将其拆分。像这样:trimws(strsplit(“ SELECT \ n blah \ n FROM foo;”,“ \ n”)[[1]])
wligtenberg

1
尽管R的最新版本具有内置功能,但它实际上只是在后台执行PERL样式的正则表达式。我可能期望一些快速的自定义C代码可以做到这一点。也许trimws正则表达式足够快。stringr::str_trim(基于stringi)也很有趣,因为它使用了完全独立的国际化字符串库。您会认为空白将不受国际化问题的影响,但我想知道。我从未见过将本机与stringr/ stringi或任何基准测试的结果进行比较。
杰克·瓦西

由于某些原因,我无法弄清楚,trimws()也没有删除我的空白行,而布莱恩trim.strings()(Bryan )的
行列

89

要操纵空格,请在stringr程序包中使用str_trim()。该软件包的手册日期为2013年2月15日,位于CRAN中。该函数还可以处理字符串向量。

install.packages("stringr", dependencies=TRUE)
require(stringr)
example(str_trim)
d4$clean2<-str_trim(d4$V2)

(贷方为评论员:R。Cotton)


2
此解决方案删除了​​一些trimws()无法删除的突变空白。
理查德·特尔福德

1
@RichardTelford您能举个例子吗?因为那可能被认为是修整中的错误。
wligtenberg '17

IMO这是最好的解决方案。没有太多的代码和高性能
彼得

感谢require(stringr)他们的文档或示例没有此必需的代码行!
pgee70

23

一个简单的功能来删除前导和尾随空格:

trim <- function( x ) {
  gsub("(^[[:space:]]+|[[:space:]]+$)", "", x)
}

用法:

> text = "   foo bar  baz 3 "
> trim(text)
[1] "foo bar  baz 3"

11

ad1)要查看空格,您可以直接print.data.frame使用修改后的参数进行调用:

print(head(iris), quote=TRUE)
#   Sepal.Length Sepal.Width Petal.Length Petal.Width  Species
# 1        "5.1"       "3.5"        "1.4"       "0.2" "setosa"
# 2        "4.9"       "3.0"        "1.4"       "0.2" "setosa"
# 3        "4.7"       "3.2"        "1.3"       "0.2" "setosa"
# 4        "4.6"       "3.1"        "1.5"       "0.2" "setosa"
# 5        "5.0"       "3.6"        "1.4"       "0.2" "setosa"
# 6        "5.4"       "3.9"        "1.7"       "0.4" "setosa"

另请参阅?print.data.frame其他选项。


9

使用grep或grepl查找带有空格的观测值,并使用sub摆脱它们。

names<-c("Ganga Din\t","Shyam Lal","Bulbul ")
grep("[[:space:]]+$",names)
[1] 1 3
grepl("[[:space:]]+$",names)
[1]  TRUE FALSE  TRUE
sub("[[:space:]]+$","",names)
[1] "Ganga Din" "Shyam Lal" "Bulbul"  

7
或者,更简洁些,"^\\s+|\\s+$"
hadley 2010年

4
只是想指出,那将不得不使用gsub而不是sub hadley的正则表达式。与sub仅如果没有前导空格...这将剥夺尾随空白
f3lix

不知道您可以在perl = FALSE中使用\ s等。文档说在这种情况下使用POSIX语法,但是接受的语法实际上是TRE regex库laurikari.net/tre/documentation/regex-syntax
Jyotirmoy Bhattacharya,2010年

5

我希望将答案作为注释添加到user56,但仍然不能这样写为独立答案。也可以通过gdata包中的trim()函数来删除前导空格和尾随空格:

require(gdata)
example(trim)

用法示例:

> trim("   Remove leading and trailing blanks    ")
[1] "Remove leading and trailing blanks"

5

如果输入之间有多个空格,则会发生另一个相关的问题:

> a <- "  a string         with lots   of starting, inter   mediate and trailing   whitespace     "

然后,您可以使用split参数的正则表达式轻松地将此字符串拆分为“真实”令牌:

> strsplit(a, split=" +")
[[1]]
 [1] ""           "a"          "string"     "with"       "lots"      
 [6] "of"         "starting,"  "inter"      "mediate"    "and"       
[11] "trailing"   "whitespace"

请注意,如果在(非空)字符串的开头存在匹配项,则输出的第一个元素为““””,但是如果在字符串的末尾存在匹配项,则输出与删除匹配项。


5

另一个选择是使用软件包中的stri_trim函数,该函数stringi默认删除前导和尾随空格:

> x <- c("  leading space","trailing space   ")
> stri_trim(x)
[1] "leading space"  "trailing space"

仅删除前导空格,请使用stri_trim_left。仅删除尾随空格,请使用stri_trim_right。当您想删除其他前导或尾随字符时,必须使用进行指定pattern =

另请参阅?stri_trim以获取更多信息。


2

我创建了一个trim.strings ()将前导和/或尾随空白修剪为的函数:

# Arguments:    x - character vector
#            side - side(s) on which to remove whitespace 
#                   default : "both"
#                   possible values: c("both", "leading", "trailing")

trim.strings <- function(x, side = "both") { 
    if (is.na(match(side, c("both", "leading", "trailing")))) { 
      side <- "both" 
      } 
    if (side == "leading") { 
      sub("^\\s+", "", x)
      } else {
        if (side == "trailing") {
          sub("\\s+$", "", x)
    } else gsub("^\\s+|\\s+$", "", x)
    } 
} 

为了说明,

a <- c("   ABC123 456    ", " ABC123DEF          ")

# returns string without leading and trailing whitespace
trim.strings(a)
# [1] "ABC123 456" "ABC123DEF" 

# returns string without leading whitespace
trim.strings(a, side = "leading")
# [1] "ABC123 456    "      "ABC123DEF          "

# returns string without trailing whitespace
trim.strings(a, side = "trailing")
# [1] "   ABC123 456" " ABC123DEF"   

1

最好的方法是trimws()

以下代码将将此功能应用于整个数据框

mydataframe <-data.frame(lapply(mydataframe,trimws),stringsAsFactors = FALSE)


或者df[] <- lapply(df, trimws)更紧凑。但是,在两种情况下,它都会将列强制转换为字符。df[sapply(df,is.character)] <- lapply(df[sapply(df,is.character)], trimws)为了安全。
Moody_Mudskipper

1

我尝试过trim()。适用于空格以及'\ n'。x ='\ n Harden,J. \ n'

修剪(x)


0
myDummy[myDummy$country == "Austria "] <- "Austria"

此后,您需要强制R不要将“奥地利”识别为等级。假设您还具有“美国”和“西班牙”两个级别:

myDummy$country = factor(myDummy$country, levels=c("Austria", "USA", "Spain"))

有点吓人,没有最高投票通过的回应,但它仍然有效。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.