【问题标题】:How can I trim leading and trailing white space?如何修剪前导和尾随空白?
【发布时间】:2011-01-16 16:38:31
【问题描述】:

我在 data.frame 中的前导和尾随空格时遇到了一些问题。

例如,我根据某个条件查看data.frame中的特定row

> 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 中做到这一点,那就太好了。

【问题讨论】:

  • 我刚刚看到sub() 也使用Perl 表示法。对于那个很抱歉。我将尝试使用该功能。但是对于我的第一个问题,我还没有解决方案。
  • 正如哈德利指出的那样,这个正则表达式 "^\\s+|\\s+$" 将识别前导和尾随空格。所以 x

标签: r whitespace trim removing-whitespace r-faq


【解决方案1】:

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

如果你想在之后清理字符串,你可以使用以下函数之一:

# Returns string without leading white space
trim.leading <- function (x)  sub("^\\s+", "", x)

# Returns string without trailing white space
trim.trailing <- function (x) sub("\\s+$", "", x)

# Returns string without leading or trailing white space
trim <- function (x) gsub("^\\s+|\\s+$", "", x)

要在myDummy$country 上使用这些功能之一:

 myDummy$country <- trim(myDummy$country)

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

 paste(myDummy$country)

这将显示由引号 (") 包围的字符串,从而更容易发现空格。

【讨论】:

  • 正如哈德利指出的那样,这个正则表达式 "^\\s+|\\s+$" 将识别前导和尾随空格。所以 x
  • 另见stringr 包中的str_trim
  • 加一个“修剪功能现在存储以备将来使用”-谢谢!
  • 不幸的是,strip.white=TRUE 仅适用于未引用的字符串。
  • 在 R 3.2.0 中有一种更简单的方法来修剪空白。看下一个答案!
【解决方案2】:

使用 grepgrepl 查找带有空格的观察值,使用 sub 去除它们。 p>

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"

【讨论】:

  • 或者,更简洁一点,"^\\s+|\\s+$"
  • 只是想指出,必须使用 gsub 而不是 sub 和 hadley 的正则表达式。使用sub,只有在没有前导空格时才会去除尾随空格...
  • 不知道你可以在 perl=FALSE 的情况下使用 \s 等。文档说在这种情况下使用 POSIX 语法,但接受的语法实际上是由 TRE 正则表达式库 laurikari.net/tre/documentation/regex-syntax 定义的超集
【解决方案3】:

广告 1) 要查看空格,您可以直接调用 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

【讨论】:

    【解决方案4】:

    要处理空白,请使用 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)

    【讨论】:

    • 此解决方案删除了​​trimws() 无法删除的一些突变空白。
    • @RichardTelford 你能举个例子吗?因为这可能被认为是 trimws 中的错误。
    • IMO 这是最好的解决方案。代码不多,高性能
    • 感谢 require(stringr) 他们的文档或示例没有此必需的代码行!
    【解决方案5】:

    一个简单的函数删除前导和尾随空格:

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

    用法:

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

    【讨论】:

      【解决方案6】:

      也可以通过 gdata 包中的 trim() 函数来删除前导和尾随空格:

      require(gdata)
      example(trim)
      

      使用示例:

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

      我更愿意将答案添加为 user56 的评论,但我还不能这样写成独立的答案。

      【讨论】:

        【解决方案7】:

        从 R 3.2.0 开始,引入了一个用于删除前导/尾随空格的新函数:

        trimws()
        

        见:Remove Leading/Trailing Whitespace

        【讨论】:

        • 这取决于最佳答案的定义。很高兴知道 (+1) 这个答案,但在快速测试中,它没有一些替代方案那么快。
        • 似乎不适用于多行字符串,尽管 \n 属于涵盖的字符类。 trimws("SELECT\n blah\n FROM foo;") 仍然包含换行符。
        • @Jubbles 这是预期的行为。在您传递给 trimws 的字符串中,没有前导或尾随空格。如果要从字符串中的每一行中删除前导和尾随空格,则首先必须将其拆分。像这样: trimws(strsplit("SELECT\n blah\n FROM foo;", "\n")[[1]])
        • 虽然是 R 最新版本的内置函数,但它确实“只是”在引擎盖下执行 PERL 样式的正则表达式。我可能期望一些快速的自定义 C 代码来执行此操作。也许trimws 正则表达式足够快。 stringr::str_trim(基于stringi)也很有趣,因为它使用了一个完全独立的国际化字符串库。您可能会认为空白不会受到国际化问题的影响,但我想知道。我从未见过原生与stringr/stringi 或任何基准的比较结果。
        • @JackWasey 我已经添加了一个基准测试——这个例子可能有点简单,但它应该可以让你了解性能
        【解决方案8】:

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

        > 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"
        

        注意,如果一个(非空)字符串的开头有匹配,则输出的第一个元素是'""',但如果字符串末尾有匹配,则输出为与删除匹配项相同。

        【讨论】:

          【解决方案9】:

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

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

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

          另请参阅?stri_trim 了解更多信息。

          【讨论】:

            【解决方案10】:

            我创建了一个 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"   
            

            【讨论】:

              【解决方案11】:
              myDummy[myDummy$country == "Austria "] <- "Austria"
              

              在此之后,您需要强制 R 不将 "Austria " 识别为一个级别。假设您也有"USA""Spain" 作为关卡:

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

              它比投票率最高的回应稍微不那么令人生畏,但它应该仍然有效。

              【讨论】:

              • 我认为这不是一个好主意,因为我们不知道 df 实际上有多少个国家/级别。此外,R 会将 Dummy$Country 的第一个元素编码为“Austria”,即使它是“Spain”。
              【解决方案12】:

              最好的方法是trimws()

              以下代码会将此函数应用于整个数据帧。

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

              【讨论】:

              • df[] &lt;- lapply(df, trimws) 更紧凑。但它会在这两种情况下强制列字符。 df[sapply(df,is.character)] &lt;- lapply(df[sapply(df,is.character)], trimws) 为了安全起见。
              【解决方案13】:

              我试过修剪()。它适用于空白以及 '\n'。

              x = '\n              Harden, J.\n              '
              
              trim(x)
              

              【讨论】:

              • 来自哪个包?该函数默认不存在。
              【解决方案14】:

              对于谁可能感兴趣,这里是一个简单的基准测试。这当然没有捕捉到所有奇怪的情况,但到目前为止,我们仍然缺少str_trim 删除空格而trimws 没有(see Richard Telford's comment to this answer)的示例。似乎无关紧要 - gsub 选项似乎是最快的:)

              x <- c(" lead", "trail ", " both ", " both and middle ", " _special")
              gsub_trim <- function (x) gsub("^\\s+|\\s+$", "", x)
              res <- microbenchmark::microbenchmark(
                gsub = gsub_trim(x),
                trimws = trimws(x),
                str_trim = stringr::str_trim(x),
                times = 10^5
              )
              res
              #> Unit: microseconds
              #>      expr    min     lq      mean median       uq       max neval cld
              #>      gsub 20.201 22.788  31.43943 24.654  28.4115  5303.741 1e+05 a  
              #>    trimws 38.204 41.980  61.92218 44.420  51.1810 40363.860 1e+05  b 
              #>  str_trim 88.672 92.347 116.59186 94.542 105.2800 13618.673 1e+05   c
              ggplot2::autoplot(res)
              

              sessionInfo()
              #> R version 4.0.3 (2020-10-10)
              #> Platform: x86_64-apple-darwin17.0 (64-bit)
              #> Running under: macOS Big Sur 10.16
              #> 
              #> locale:
              #> [1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
              #> 
              #> attached base packages:
              #> [1] stats     graphics  grDevices utils     datasets  methods   base     
              #> 
              #> loaded via a namespace (and not attached):
              #>  stringr_1.4.0  
              
              

              【讨论】:

                【解决方案15】:

                使用 dplyr/tidyverse mutate_allstr_trim 修剪整个数据框:

                myDummy %>%
                  mutate_all(str_trim)
                
                library(tidyverse)
                set.seed(335)
                df <- mtcars %>%
                        rownames_to_column("car") %>%
                        mutate(car = ifelse(runif(nrow(mtcars)) > 0.4, car, paste0(car, " "))) %>%
                        select(car, mpg)
                
                print(head(df), quote = T)
                #>                    car    mpg
                #> 1         "Mazda RX4 " "21.0"
                #> 2      "Mazda RX4 Wag" "21.0"
                #> 3        "Datsun 710 " "22.8"
                #> 4    "Hornet 4 Drive " "21.4"
                #> 5 "Hornet Sportabout " "18.7"
                #> 6           "Valiant " "18.1"
                
                df_trim <- df %>%
                  mutate_all(str_trim)
                
                print(head(df_trim), quote = T)  
                #>                   car    mpg
                #> 1         "Mazda RX4"   "21"
                #> 2     "Mazda RX4 Wag"   "21"
                #> 3        "Datsun 710" "22.8"
                #> 4    "Hornet 4 Drive" "21.4"
                #> 5 "Hornet Sportabout" "18.7"
                #> 6           "Valiant" "18.1"
                

                reprex package (v0.3.0) 于 2021-05-07 创建

                【讨论】:

                  猜你喜欢
                  • 2013-03-04
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-09-12
                  相关资源
                  最近更新 更多