【问题标题】:Regex expression to exclude hyphenated words in R正则表达式以排除 R 中的连字符
【发布时间】:2015-09-29 20:30:44
【问题描述】:

我正在使用 R 来标记一组文本;在标记化之后,我最终得到一个 char 向量,其中保留了标点符号、撇号和连字符。比如我有这个原文

txt <- "this ain't a Hewlett-Packard box - it's an Apple box, a very nice one!"

在标记化之后(我使用包 tm 中的 scan_tokenizer 执行)我得到以下字符向量

   > vec1
 [1] "this"            "ain't"           "a"               "Hewlett-Packard"
 [5] "box"             "-"               "it's"            "an"             
 [9] "Apple"           "box,"            "a"               "very"           
[13] "nice"            "one!"           

现在为了去掉标点符号,我做了以下操作

vec2 <- gsub("[^[:alnum:][:space:]']", "", vec1)

也就是说,我将所有不是字母数字值、空格和撇号的东西都替换为“”;然而这是结果

> vec2
 [1] "this"           "ain't"          "a"              "HewlettPackard" "box"           
 [6] ""               "it's"           "an"             "Apple"          "box"           
[11] "a"              "very"           "nice"           "one"    

我想将连字符 sych 保留为“Hewlett-Pacakard”,同时摆脱单独的连字符。基本上,我需要一个正则表达式来排除 vec2 的 gsub 表达式中的 \w-\w 形式的连字符。

欢迎您提出建议

【问题讨论】:

    标签: regex r


    【解决方案1】:

    我建议两种方法,第一,尽可能简单,第二,尽可能使用 Unicode 字符类,特别是对于各种文本处理器可能会替换其他字符的连字符(例如参见 http://www.fileformat.info/info/unicode/category/Pd/list.htm) .

    所以:

    最简单(也非常快),只检测连字符的二进制匹配:

    vec1[!(vec1 %in% "-")]
    

    更好(从 Unicode 的角度来看),也相当快:

    vec1[!stringi::stri_detect_regex(vec1, "^\\p{Pd}$")]
    

    最后一个使用 Unicode 字符类Pd,表示“破折号或连字符标点符号”。这包括不间断的连字符、破折号等,正则表达式开头和结尾的^$ 意味着这将是一个独立的字符。

    【讨论】:

      【解决方案2】:

      如果您只是想删除“纯连字符”,请使用模式'^-$'(因为连字符不是正则表达式元字符。

      vec2 <- vec1[!grepl( '^-$' , vec1) ]
      

      如果您想删除“各种裸标点符号”,可能是:

      vec2 <- vec1[!grepl( '^[[:punct:]]$' , vec1) ]
      

      【讨论】:

        【解决方案3】:

        这是一种使用带有单词边界 (\b) 和非单词字符 (\W,相当于 [^[:alnum:]_]) 的 strsplit 的方法

        strsplit(txt, "\\b | \\b|\\W |\\W$")
        #[[1]]
        # [1] "this"            "ain't"           "a"               "Hewlett-Packard"
        # [5] "box"             ""                "it's"            "an"             
        # [9] "Apple"           "box"             "a"               "very"           
        #[13] "nice"            "one"            
        

        或者对于单独的连字符而不是 "" 不返回任何内容。

        strsplit(txt, "\\b | \\b| ?\\W |\\W$")
        #[[1]]
        # [1] "this"            "ain't"           "a"               "Hewlett-Packard"
        # [5] "box"             "it's"            "an"              "Apple"          
        # [9] "box"             "a"               "very"            "nice"
        #[13] "one"
        

        【讨论】:

          【解决方案4】:

          你可以试试这个,

          > library(stringr)    
          > txt <- "this ain't a Hewlett-Packard box - it's an Apple box, a very nice one!"
          > gsub("(?!\\b['-]\\b|\\s)[\\W_]", "", str_extract_all(txt, "\\S+")[[1]], perl=T)
           [1] "this"            "ain't"           "a"              
           [4] "Hewlett-Packard" "box"             ""               
           [7] "it's"            "an"              "Apple"          
          [10] "box"             "a"               "very"           
          [13] "nice"            "one"  
          

          > strsplit(gsub('(?!\\b[[:punct:]]\\b|\\s)[\\W_]', '', txt,perl=T), ' ')[[1]]
           [1] "this"            "ain't"           "a"              
           [4] "Hewlett-Packard" "box"             ""               
           [7] "it's"            "an"              "Apple"          
          [10] "box"             "a"               "very"           
          [13] "nice"            "one" 
          

          【讨论】:

            【解决方案5】:
            strsplit(gsub("[^[:alnum:][:space:]'-]", "", txt), '\\s|\\ - ')
            

            【讨论】:

              【解决方案6】:
              strsplit(gsub('[[:punct:]](?!\\w)', '', txt, perl=T), ' ')[[1]]
               #[1] "this"            "ain't"           "a"              
               #[4] "Hewlett-Packard" "box"             ""               
               #[7] "it's"            "an"              "Apple"          
              #[10] "box"             "a"               "very"           
              #[13] "nice"            "one"
              

              或者您可以这样做以在“一”之后保留感叹号:

              strsplit(gsub('(?<!\\w)[[:punct:]](?!\\w)', '', txt,perl=T), ' ')[[1]]
              #  [1] "this"            "ain't"           "a"              
              #  [4] "Hewlett-Packard" "box"             ""               
              #  [7] "it's"            "an"              "Apple"          
              # [10] "box,"            "a"               "very"           
              # [13] "nice"            "one!"
              

              我正在使用正则表达式lookbehinds 和lookaheads。模式(?!\\w) 是一个前瞻(更准确地说,是一个负前瞻),它告诉评估者删除所有标点符号,除了那些后面跟着一个字母或数字的标点符号。在第二种模式中,(?&lt;!\\w) 被认为是负面的后视。它将删除所有标点符号,除了字母或数字之后的标点符号。为了帮助记住差异,向后看“向后”看下一个标记,向前看“向上”看前面的内容。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-09-16
                • 1970-01-01
                • 1970-01-01
                • 2017-04-13
                • 2019-08-03
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多