Ruby string char chunking

时间:2016-05-17 01:58:22

标签: ruby regex

我有一个字符串" wwwggfffw"并希望将其分解为数组,如下所示:

  ["www", "gg", "fff", "w"]

有没有办法用正则表达式做到这一点?

5 个答案:

答案 0 :(得分:7)

"wwwggfffw".scan(/((.)\2*)/).map(&:first)

scan有点搞笑,因为它会返回匹配或子组,具体取决于是否有子组;我们需要使用子组来确保重复相同的字符((.)\1),但如果它返回整个匹配而不仅仅是重复的字母,我们更喜欢它。所以我们需要将整个匹配组成一个子组,以便捕获它,最后我们需要提取匹配(没有其他子组),我们使用.map(&:first)

编辑解释正则表达式((.)\2*)本身:

(   start group #1, consisting of
(     start group #2, consisting of
.       any one character
)       and nothing else
\2    followed by the content of the group #2
*       repeated any number of times (including zero)
)     and nothing else.

因此,在wwwggfffw中,(.)w捕获到第2组;然后\2*会抓取任何额外数量的w。这使得组#1捕获www

答案 1 :(得分:3)

您可以使用back references,例如

'wwwggfffw'.scan(/((.)\2*)/).map{ |s| s[0] }

将起作用

答案 2 :(得分:1)

这是一个不使用正则表达式但效果不错的人:

<?php
                    if (is_array($result))
                    foreach($result as $row){
                        echo '
                            <li>
                                <a href="#">
                                     <img class="left" src="images/user/' .
                    $row['image'] . '" alt="picture">
                    </a>
                    <div class="content left">
                    <a href="#">' . $row['name'] . '</a>
                    <div class="status">' . $row['status'] . '</div>
                    <span class="localtime" data-timestamp="' .
                    $row['timestamp'] . '"></span>
                  </div>
                    <div class="clearer"></div>
                    </li>
                    ';
                    }
                    ?>

在我的基准测试中,它比这里的正则表达式答案更快(至少使用你给出的示例字符串)。

答案 3 :(得分:0)

另一个非正则表达式解决方案,这个使用Enumerable#slice_when,它在Ruby v.2.2中首次亮相:

str.each_char.slice_when { |a,b| a!=b }.map(&:join)
  #=> ["www", "gg", "fff", "w"]

另一种选择是:

str.scan(Regexp.new(str.squeeze.each_char.map { |c| "(#{c}+)" }.join)).first
  #=> ["www", "gg", "fff", "w"] 

这里的步骤如下

s = str.squeeze
  #=> "wgfw" 
a = s.each_char
  #=> #<Enumerator: "wgfw":each_char>

此枚举器生成以下元素:

a.to_a
  #=> ["w", "g", "f", "w"]

继续

b = a.map { |c| "(#{c}+)" }
  #=> ["(w+)", "(g+)", "(f+)", "(w+)"] 
c = b.join
  #=> "(w+)(g+)(f+)(w+)" 
r = Regexp.new(c)
  #=> /(w+)(g+)(f+)(w+)/ 
d = str.scan(r)
  #=> [["www", "gg", "fff", "w"]] 
d.first
  #=> ["www", "gg", "fff", "w"] 

答案 4 :(得分:0)

这是在没有正则表达式的情况下执行此操作的另一种方法:

'wwwggfffw'.chars.chunk(&:itself).map{ |s| s[1].join }
# => ["www", "gg", "fff", "w"]