【问题标题】:Partition/split a string by character set in Ruby在 Ruby 中按字符集对字符串进行分区/拆分
【发布时间】:2013-08-29 13:53:59
【问题描述】:

如何分隔字符串中的不同字符集?例如,如果我有这些字符集:

[a-z]
[A-Z]
[0-9]
[\s]
{everything else}

这个输入:

thisISaTEST***1234pie

然后我想分隔不同的字符集,例如,如果我使用换行符作为分隔符:

this
IS
a
TEST
***
1234
pie

我已经尝试过这个正则表达式,并且具有积极的前瞻性:

'thisISaTEST***1234pie'.gsub(/(?=[a-z]+|[A-Z]+|[0-9]+|[\s]+)/, "\n")

但显然+s 并没有贪心,因为我得到了:

t
h
# (snip)...
S
T***
1
# (snip)...
e

我剪掉了不相关的部分,但正如您所见,每个字符都算作自己的字符集,{everything else} 字符集除外。

我该怎么做?它不一定必须是正则表达式。将它们拆分成一个数组也可以。

【问题讨论】:

  • (抱歉标题太糟糕了;我想不出更好的了。如果你明白我想要什么,请进行编辑,你可以想出一个更好的。:)

标签: ruby regex split


【解决方案1】:

困难的部分是匹配与正则表达式其余部分不匹配的任何内容。忘记这一点,想想一种可以将不匹配的部分与匹配的部分混合在一起的方法。

"thisISaTEST***1234pie"
.split(/([a-z]+|[A-Z]+|\d+|\s+)/).reject(&:empty?)
# => ["this", "IS", "a", "TEST", "***", "1234", "pie"]

【讨论】:

    【解决方案2】:

    在 ASCII 字符集中,除了字母数字和空格外,还有 32 个“标点”字符,与属性构造 \p{punct} 匹配。

    要将您的字符串拆分为单个类别的序列,您可以编写

    str = 'thisISaTEST***1234pie'
    p str.scan(/\G(?:[a-z]+|[A-Z]+|\d+|\s+|[\p{punct}]+)/)
    

    输出

    ["this", "IS", "a", "TEST", "***", "1234", "pie"]
    

    或者,如果您的字符串包含 ASCII 集之外的字符,您可以按照属性编写整个内容,如下所示

    p str.scan(/\G(?:\p{lower}+|\p{upper}+|\p{digit}+|\p{space}|[^\p{alnum}\p{space}]+)/)
    

    【讨论】:

    • 我不希望只有标点符号,我希望任何其他字符也能正常工作。
    • 我试图解释在字母数字和空格之后剩下的就是标点符号(和控制字符)。当然,如果您的数据包含 ASCII 集之外的字符,这将不起作用。
    【解决方案3】:

    这里有两个解决方案。

    String#scan 带正则表达式

    str = "thisISa\n TEST*$*1234pie"
    
    r = /[a-z]+|[A-Z]+|\d+|\s+|[^a-zA-Z\d\s]+/
    str.scan r
      #=> ["this", "IS", "a", "\n ", "TEST", "*$*", "1234", "pie"]
    

    由于^[^a-zA-Z\d\s] 的开头,该字符类匹配任何字符除了 字母(大小写)、数字和空格。

    使用Enumerable#slice_when1

    首先,一个辅助方法:

    def type(c)
      case c
      when /[a-z]/ then 0
      when /[A-Z]/ then 1
      when /\d/    then 2
      when /\s/    then 3
      else              4
      end
    end
    

    例如,

    type "f"   #=> 0
    type "P"   #=> 1
    type "3"   #=> 2
    type "\n"  #=> 3
    type "*"   #=> 4    
    

    然后

    str.each_char.slice_when { |c1,c2| type(c1) != type(c2) }.map(&:join)
      #=> ["this", "IS", "a", "TEST", "***", "1234", "pie"]
    

    1. slich_when 在 Ruby v2.4 中首次亮相。

    【讨论】:

      【解决方案4】:

      非单词、非空格字符可以用[^\w\s] 覆盖,所以:

      "thisISaTEST***1234pie".scan /[a-z]+|[A-Z]+|\d+|\s+|[^\w\s]+/
      #=> ["this", "IS", "a", "TEST", "***", "1234", "pie"]
      

      【讨论】:

      • @sawa - _ 是一个字符,但它不适合任何这些组,所以不清楚它属于哪里。
      • 它显然属于 OP 的 everything else,但它不适合您的正则表达式。
      • @sawa 将_ 放入everything else(?:[^\w\s]|_)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-20
      • 2015-08-09
      • 2016-08-25
      相关资源
      最近更新 更多