【问题标题】:How can the pattern of a string split become the substring itself?字符串拆分的模式如何成为子字符串本身?
【发布时间】:2020-01-21 19:20:57
【问题描述】:

我正在清理 R 中的一些字符串,我需要将它们拆分以从两个不属于彼此的子字符串中恢复信息。问题是,我没有真正的模式来分割所有的字符串。相反,我知道我正在寻找的不同子字符串是什么,并且我希望将它们用作执行拆分的模式,而不会在此过程中丢失此模式本身。

假设一个字符串样本的形式为:

test <- c("Some string that explains x. Conflict", 
          "Some string that explains y. Additional information. Precaution",
          "Some string that explains z. Justification.   Conflict") 

我希望将这些字符串拆分为以下列表:

[1] "Some string that explains x."
[2] "Conflict"
[3] "Some string that explains y. Additional information."
[4] "Precaution"
[5] "Some string that explains z. Justification."
[6] "Conflict"

我的问题的核心是我需要保存订单。

显然,我提到的模式是:

pattern <- c("Conflict", "Precaution")

我最初的大多数字符串在解释部分和所谓的模式之间都有一个双空格,所以我可以简单地使用

unlist(strsplit(test, "\\s{2,}"))

区分它们。我现在意识到其中一些在它们之间只有一个空格,并且这种方法不再起作用,因为解释性字符串最终会被划分为每个单独的单词。

提取它们是我查找的一个选项,但是当我尝试时,我会丢失我必须保留的顺序(我最终创建了一个仅包含提取的子字符串的新列表)。

对于strsplit(),我不能将上述模式用于函数,因为通过用它拆分字符串,我删除了模式本身。我尝试使用我发现的 gsub() 技巧用“~”包围模式,然后相应地拆分它,但我发现自己没有成功。

即,

 > unlist(strsplit(test, pattern))
[1] "Some string that explains x. "                        
[2] "Some string that explains y. Additional information. "
[3] "Some string that explains z. Justification.   "

本质上,我如何使用上述模式拆分字符串并获得所需的结果?或者,有没有办法从原始字符串中提取模式并以正确的顺序将它们插入到列表中?

【问题讨论】:

  • 只有“冲突”和“预防”这两个词是您想要寻找的吗?字符串末尾是否还会出现您特别不想查找的其他内容?
  • @HaydenY。我通过你的问题意识到我应该更准确。我还有更多单词要查找(大约 10 个)。实际上,我正在排序的数据有超过 20 000 个字符串,老实说,我不知道字符串末尾是否会出现我不想要的东西。这实际上是引发问题的原因,因为我确切地知道模式并且我知道我希望检索它。

标签: r regex string split strsplit


【解决方案1】:

鉴于您可能有不想发现的病例,我的建议如下:

test <- c("Some string that explains x. Conflict",
          "Some string that explains y. Additional information. Precaution",
          "Some string that explains z. Justification.   Conflict",
          "A String You Don't Want Conflict",
          "Another string you don't want that ends with a single word.  Word" )

pattern <- c("Conflict", "Precaution") # Plus the other ~8 words you want
pattern.regex<-paste0("(\\.|\\?|!)\\s+(", paste(pattern, collapse="|"), ")$") # Pattern for punctuation that ends a sentence, one or more spaces, the words you want, and the end of a string

test2<-test[grep(pattern.regex, test, perl=T)] # A version of test without irrelevant values

然后您可以像 akrun 的回答那样拆分 test2 中的每个字符串(无需指定特定的单词,因为我们已经限制 test2 只包含以您想要的单词之一结尾的案例。

unlist(strsplit(test2, "(?<=\\.) +(?=\\S+$)", perl = TRUE))

也就是说,您可能需要考虑更多的事情,例如

  • “冲突”之类的词后面可以有句号吗?
  • 它们必须以大写字母开头,还是全部小写/大写?
  • 您是否需要像 test 的第四个元素这样的情况,即在最后一个单词之前的句段末尾没有句点?

最终,我的建议是尝试上述方法并稍微挖掘您的数据集,看看结果是太宽泛还是太窄。但这至少涵盖了基本概念,并为原始数据的外观提供了一定程度的不确定性。

【讨论】:

    【解决方案2】:

    如果您将两个模式组合成一个元素patt,并用'|' 分隔它们,则该新模式将匹配test 向量中的两个原始模式之一。然后使用str_remove 可以得到没有模式的部分,使用str_extract 可以得到匹配模式之一的部分。现在您可以使用c(rbind(x, y))* 模式将这两个向量交织成一个向量。与直接使用正则表达式来获取我假设的非模式部分和模式部分相比,这在计算上的效率会更低。

    注意:所有这些都假设您要提取的模式只是“冲突”或“预防”,并且它们可以出现在字符串的任何位置。这与其他一些答案中的逻辑不同,这些答案没有识别这两个单词,而是识别字符串的最后一部分。我不完全清楚你想要哪个,所以仅供参考。

    library(stringr)
    patt <- paste(pattern, collapse = '|')
    c(rbind(str_remove(test, patt), str_extract(test, patt)))
    
    # [1] "Some string that explains x. "                        
    # [2] "Conflict"                                             
    # [3] "Some string that explains y. Additional information. "
    # [4] "Precaution"                                           
    # [5] "Some string that explains z. Justification.   "       
    # [6] "Conflict" 
    

    * 请参见下面的示例。这是可行的,因为c 会将矩阵按列转换为向量,并且您通过将向量合并在一起来创建矩阵,其中每列的每个向量都有一个元素。

    c(rbind(c('a', 'b', 'c'), c('A', 'B', 'C')))
    #[1] "a" "A" "b" "B" "c" "C"
    

    【讨论】:

    • 你能解释一下吗?不完全遵循逻辑
    【解决方案3】:

    一个选项是在最后一个空格处分割。在这里,我们使用正则表达式环视,即匹配一个或多个空格 (+),该空格在 . (?&lt;=\\.) 之后并在一个或多个非空白字符 (\\S+) 之前直到结尾 ($ ) 的字符串

    library(tidyr)
    library(tibble)
    tibble(test) %>%
         separate_rows(test,  sep="(?<=\\.) +(?=\\S+$)")
    # A tibble: 6 x 1
    #  test                                                
    #  <chr>                                               
    #1 Some string that explains x.                        
    #2 Conflict                                            
    #3 Some string that explains y. Additional information.
    #4 Precaution                                          
    #5 Some string that explains z. Justification.         
    #6 Conflict                                            
    

    或者在base R中使用相同的正则表达式

    unlist(strsplit(test, "(?<=\\.) +(?=\\S+$)", perl = TRUE))
    

    如果在我们需要拆分之前有特定的词向量,则基于该向量创建正则表达式

    pat <- paste0("\\s+(?=\\b(", paste(pattern, collapse="|"), ")\\b)")
    

    并在strsplit中使用它

    unlist(strsplit(test, pat, perl = TRUE))
    #[1] "Some string that explains x."              
    #[2] "Conflict" 
    #[3] "Some string that explains y. Additional information."
    #[4] "Precaution"                                          
    #]5] "Some string that explains z. Justification." 
    #[6] "Conflict"                          
    

    【讨论】:

      【解决方案4】:

      另一个 将在最后一个. 拆分:

      unlist(strsplit(test, "\\.\\s*(?=[^\\.]+$)", perl=TRUE))
      
      # [1] "Some string that explains x"                         "Conflict" 
      # [3] "Some string that explains y. Additional information" "Precaution"
      # [5] "Some string that explains z. Justification"          "Conflict" 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-22
        • 2011-11-25
        • 2016-12-01
        相关资源
        最近更新 更多