如何将字符串转换为Ruby中保留空格的数组



如何将String:'Hello world!'转换为保留所有空格的数组['Hello', ' ', 'world!']

我尝试使用具有不同参数的split方法转换字符串,但没有找到正确的解决方案。

此外,我在文档中没有找到任何其他适合解决这个问题的方法(Class:String(Ruby 3.1.0((。

我刚刚想到,你可以使用scan。假设您的字符串存储在变量s中,并且您希望将空间区域和非空间区域分开,则可以执行

s.scan(/[ ]+|[^ ]+/)

在你的情况下会产生

["Hello", "   ", "world!"]

使用String#scan而不是String#split

您不想使用String#split,因为这不会保留您的空间。您希望使用String#扫描或String#分区。使用Unicode字符属性,您可以扫描匹配:

'Hello   world!'.scan /[p{Alnum}p{Punct}]+|p{Space}+/
#=> ["Hello", "   ", "world!"]

如果您愿意,也可以使用POSIX字符类(在Ruby中发音为"括号表达式"(来做同样的事情。例如:

'Hello   world!'.scan /[[:alnum:][:punct:]]+|[[:space:]]+/
#=> ["Hello", "   ", "world!"]

这两种选项中的任何一种都将比仅依赖ASCII字符或文字空白原子的解决方案更强大,但如果您知道字符串不包括其他类型的字符或编码,那么这些解决方案也会起作用。

慎用元符求简洁

如果您希望正则表达式简洁,并且确信不需要关心Unicode字符或明确区分非空白字符和标点符号,那么也可以使用sS元字符。例如:

'Hello   world!'.scan /s+|S+/
#=> ["Hello", "   ", "world!"]

这通常不如上面的字符属性或括号表达式健壮,但仍然清晰、简短且易于阅读。它适合您的示例,因此值得一提,但S元字符可以匹配控制字符和其他意外的东西,因此您需要谨慎使用它,除非您真正了解您的数据。例如,您的字符串可能包含一个不可见的NUL或像CTRL-D这样的控制字符,在这种情况下,S会捕获它并返回一个Unicode转义字符:

"x00".scan /S+/
#=> ["u0000"]
?C-D.scan /S+/
#=> ["u0004"]

这可能不是你所期望的,但考虑到更大的数据集,这种类型的事情不可避免地会发生。你越明确,你的生产数据可能出现的问题就越少。

使用String#分区

对于原始示例中非常简单的用例,您只有两个用空格分隔的单词。这意味着您还可以使用String#分区对连续的空白进行分区。这将把字符串分成三个元素,保留分隔单词的空白。例如:

'Hello   world!'.partition /s+/
#=> ["Hello", "   ", "world!"]

分区方法虽然更简单,但对于较长的字符串(如:(则不能很好地工作

'Goodbye   cruel world!'.partition /s+/
#=> ["Goodbye", "   ", "cruel world!"]

因此String#scan对于一般用例来说将是一种更好、更灵活的方法。然而,无论何时,只要您想将字符串拆分为三个元素,或者想保留分区元素本身,#partition都会非常方便。

您可以继续使用split,并通过使用带有capture group:的简单regex来保留空间

"Hello   World  ! ".split(/( +)/)
#=>  ["Hello", "   ", "World", "  ", "!", " "]

我所知道的唯一一个问题是,以空格开头的字符串将导致以空字符串开头的数组:

"  Hello   World  ! ".split(/( +)/)
#=>  ["", "  ", "Hello", "   ", "World", "  ", "!", " "]

如果这是一个问题,您可以在混合物中添加类似drop_while的东西:

"  Hello   World  ! ".split(/( +)/).drop_while(&:empty?)
#=>  ["  ", "Hello", "   ", "World", "  ", "!", " "]

最新更新