【问题标题】:split strings on first and last commas在第一个和最后一个逗号上拆分字符串
【发布时间】:2014-05-30 18:18:52
【问题描述】:

我想在第一个和最后一个逗号处分割字符串。每个字符串至少有两个 逗号。下面是一个示例数据集和所需的结果。

这里有一个类似的问题询问如何拆分第一个逗号:Split on first comma in string

这里我问了如何拆分前两个冒号上的字符串:Split string on first two colons

感谢您的任何建议。我更喜欢 base R 中的解决方案。抱歉,如果这是重复的。

my.data <- read.table(text='

my.string        some.data
123,34,56,78,90     10
87,65,43,21         20
a4,b6,c8888         30
11,bbbb,ccccc       40
uu,vv,ww,xx         50
j,k,l,m,n,o,p       60', header = TRUE, stringsAsFactors=FALSE)

desired.result <- read.table(text='

 my.string1 my.string2 my.string3 some.data
        123   34,56,78         90        10
         87      65,43         21        20
         a4         b6      c8888        30
         11       bbbb      ccccc        40
         uu      vv,ww         xx        50
          j  k,l,m,n,o          p        60', header = TRUE, stringsAsFactors=FALSE)

【问题讨论】:

    标签: regex string r split


    【解决方案1】:

    您可以使用\K 运算符将已匹配的文本保留在结果之外,并使用否定的前瞻性断言来执行此操作(嗯,几乎,开头有一个烦人的逗号我还没有在strsplit 中删除的中间部分)。但我喜欢这个作为构建正则表达式的练习......

    x <- '123,34,56,78,90'
    strsplit( x , "^[^,]+\\K|,(?=[^,]+$)" , perl = TRUE )
    #[[1]]
    #[1] "123"       ",34,56,78" "90"
    

    解释:

    • ^[^,]+ :从字符串的开头匹配一个或多个 not 的字符 ,
    • \\K : 但不要在匹配中包含那些匹配的字符
    • 所以第一个匹配是第一个逗号...
    • | : 或者你可以匹配...
    • ,(?=[^,]+$) :一个,,只要它后跟[(?=...)] 一个或多个不是 , 的字符,直到字符串的末尾($)。 ..

    【讨论】:

    • +1,但你在\K 之后缺少,,因为他不希望在比赛中拆分,。我建议将正则表达式更改为 ^[^,]+\K,|,(?=[^,]+$)^\w+\K,|,(?=\w+$)
    • @zx81 试试看。你不会得到你所期望的。这样想 - 问:如果你添加你建议的逗号,那么有多少逗号会匹配正则表达式?答:全部!您的其他建议也不会达到您的预期。
    • 西蒙,我试过了。我给你的第二个解决方案是我独立提出的,我不想发布它以免与您竞争,因为解决方案非常接近。这是demo,你可以看到它只匹配正确的逗号。这是demo of your one,我建议使用额外的逗号。
    • @zx81 让我更具体一些 - 在 R 中尝试一下。我不知道为什么它不能按您的预期工作,但事实并非如此。一定与贪心匹配有关。顺便说一句,我毫不怀疑您是独立提出来的!
    • @zx81 这实际上很奇怪......使用m &lt;- gregexpr( '^\\w+\\K,|,(?=\\w+$)' , x , perl = TRUE );regmatches( x , m ) 显示返回了所需的匹配项;每行只有两个逗号,(其中x 是演示中字符串的字符向量)。
    【解决方案2】:

    这是一个相对简单的方法。在第一行中,我们使用sub 将第一个和最后一个逗号替换为产生s 的分号。然后我们使用sep=";" 读取s,最后使用cbind 读取my.data 的其余部分:

    s <- sub(",(.*),", ";\\1;", my.data[[1]])
    DF <- read.table(text=s, sep =";", col.names=paste0("mystring",1:3), as.is=TRUE)
    cbind(DF, my.data[-1])
    

    给予:

      mystring1 mystring2 mystring3 some.data
    1       123  34,56,78        90        10
    2        87     65,43        21        20
    3        a4        b6     c8888        30
    4        11      bbbb     ccccc        40
    5        uu     vv,ww        xx        50
    6         j k,l,m,n,o         p        60
    

    【讨论】:

      【解决方案3】:

      这里是分割第一个和最后一个逗号的代码。这段代码很大程度上来自@bdemarest 的答案:Split string on first two colons 下面的gsub 模式是答案的核心,包含重要的差异。字符串拆分后新建数据框的代码和@bdemarest一样

      # Replace first and last commas with colons.
      
      new.string <- gsub(pattern="(^[^,]+),(.+),([^,]+$)", 
                    replacement="\\1:\\2:\\3", x=my.data$my.string)
      new.string
      
      # Split on colons
      split.data <- strsplit(new.string, ":")
      
      # Create data frame
      new.data <- data.frame(do.call(rbind, split.data))
      names(new.data) <- paste("my.string", seq(ncol(new.data)), sep="")
      
      my.data$my.string <- NULL
      my.data <- cbind(new.data, my.data)
      my.data
      
      #   my.string1 my.string2 my.string3 some.data
      # 1        123   34,56,78         90        10
      # 2         87      65,43         21        20
      # 3         a4         b6      c8888        30
      # 4         11       bbbb      ccccc        40
      # 5         uu      vv,ww         xx        50
      # 6          j  k,l,m,n,o          p        60
      
      
      
      # Here is code for splitting strings on the first comma
      
      my.data <- read.table(text='
      
      my.string        some.data
      123,34,56,78,90     10
      87,65,43,21         20
      a4,b6,c8888         30
      11,bbbb,ccccc       40
      uu,vv,ww,xx         50
      j,k,l,m,n,o,p       60', header = TRUE, stringsAsFactors=FALSE)
      
      
      # Replace first comma with colon
      
      new.string <- gsub(pattern="(^[^,]+),(.+$)", 
                         replacement="\\1:\\2", x=my.data$my.string)
      new.string
      
      # Split on colon
      split.data <- strsplit(new.string, ":")
      
      # Create data frame
      new.data <- data.frame(do.call(rbind, split.data))
      names(new.data) <- paste("my.string", seq(ncol(new.data)), sep="")
      
      my.data$my.string <- NULL
      my.data <- cbind(new.data, my.data)
      my.data
      
      #   my.string1  my.string2 some.data
      # 1        123 34,56,78,90        10
      # 2         87    65,43,21        20
      # 3         a4    b6,c8888        30
      # 4         11  bbbb,ccccc        40
      # 5         uu    vv,ww,xx        50
      # 6          j k,l,m,n,o,p        60
      
      
      
      
      # Here is code for splitting strings on the last comma
      
      my.data <- read.table(text='
      
      my.string        some.data
      123,34,56,78,90     10
      87,65,43,21         20
      a4,b6,c8888         30
      11,bbbb,ccccc       40
      uu,vv,ww,xx         50
      j,k,l,m,n,o,p       60', header = TRUE, stringsAsFactors=FALSE)
      
      
      # Replace last comma with colon
      
      new.string <- gsub(pattern="^(.+),([^,]+$)", 
                         replacement="\\1:\\2", x=my.data$my.string)
      new.string
      
      # Split on colon
      split.data <- strsplit(new.string, ":")
      
      # Create new data frame
      new.data <- data.frame(do.call(rbind, split.data))
      names(new.data) <- paste("my.string", seq(ncol(new.data)), sep="")
      
      my.data$my.string <- NULL
      my.data <- cbind(new.data, my.data)
      my.data
      
      #     my.string1 my.string2 some.data
      # 1 123,34,56,78         90        10
      # 2     87,65,43         21        20
      # 3        a4,b6      c8888        30
      # 4      11,bbbb      ccccc        40
      # 5     uu,vv,ww         xx        50
      # 6  j,k,l,m,n,o          p        60
      

      【讨论】:

        【解决方案4】:

        你可以在那个专栏里做一个简单的strsplit

        popshift<-sapply(strsplit(my.data$my.string,","), function(x) 
            c(x[1], paste(x[2:(length(x)-1)],collapse=","), x[length(x)]))
        
        desired.result <- cbind(data.frame(my.string=t(popshift)), my.data[-1])
        

        我只是拆分了所有的值,并用第一个、最后一个和中间的字符串创建了一个新向量。然后我将其与其余数据绑定。结果是

          my.string.1 my.string.2 my.string.3 some.data
        1         123    34,56,78          90        10
        2          87       65,43          21        20
        3          a4          b6       c8888        30
        4          11        bbbb       ccccc        40
        5          uu       vv,ww          xx        50
        6           j   k,l,m,n,o           p        60
        

        【讨论】:

        • @MarkMiller -- 啊,但是"," 一个(非常简单的)regex
        【解决方案5】:

        使用 stringr 包中的 str_match(),并从您的一个链接中获得一点帮助,

        > library(stringr)
        > data.frame(str_match(my.data$my.string, "(.+?),(.*),(.+?)$")[,-1], 
                     some.data = my.data$some.data)
        #    X1        X2    X3 some.data
        # 1 123  34,56,78    90        10
        # 2  87     65,43    21        20
        # 3  a4        b6 c8888        30
        # 4  11      bbbb ccccc        40
        # 5  uu     vv,ww    xx        50
        # 6   j k,l,m,n,o     p        60
        

        【讨论】:

          猜你喜欢
          • 2021-11-16
          • 1970-01-01
          • 2023-03-27
          • 2011-11-25
          • 2015-08-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-31
          相关资源
          最近更新 更多