使用正则表达式在Ruby中分割字符串时保留模式字符

10
我有以下字符串
str="HelloWorld How areYou I AmFine"

我希望你能将这个字符串转换为以下数组。
["Hello","World How are","You I Am", "Fine"]

我一直在使用以下正则表达式,它可以正确分割文本,但也省略了匹配模式,我还想保留该模式。

str.split(/[a-z][A-Z]/)
 => ["Hell", "orld How ar", "ou I A", "ine"] 

它忽略了匹配模式。

有人能帮我保留这些字符在结果数组中吗?

3个回答

7
Ruby 1.9 中,您可以使用正向先行断言和正向后行断言(也称为零宽度断言的前瞻和后顾正则表达式构造)。它们匹配字符,但然后放弃匹配并仅返回结果,因此您不会丢失边界字符:
str.split /(?<=[a-z])(?=[A-Z])/
=> ["Hello", "World How are", "You I Am", "Fine"] 

Ruby 1.8不支持向前/向后查找构造。如果可能的话,建议使用Ruby 1.9。

如果你被迫使用Ruby 1.8.7,我认为正则表达式对你没有帮助,我能想到的最好解决方案是构建一个简单的状态机:遍历原始字符串中的每个字符,并构建第一个字符串,直到遇到边界条件,然后再构建第二个字符串等。


谢谢您的回答,但是它给了我以下错误:ruby-1.8.7-p302 > str="HelloWorld How areYou I AmFine" => "HelloWorld How areYou I AmFine" ruby-1.8.7-p302 > str.split /(?<=[a-z])(?=[A-Z])/ SyntaxError: compile error (irb):987: undefined (?...) sequence: /(?<=[a-z])(?=[A-Z])/ from (irb):987 from :0 - Nadeem Yasin
那么在1.8版本中有什么解决方案呢?我必须使用1.8.7版本。 - Nadeem Yasin
我从我的同事那里找到了答案,对于1.8.7,可以按照以下步骤操作。str.underscore.split(/_/).each do |s| s.capitalize! end - Nadeem Yasin
@alex-kliuchnikau,你可以使用#scan而不是#split来完成1.8版本的操作。这样就不需要使用lookbehind了。 - dbenhur

5
迄今为止有三个答案,每个答案都有限制:一个仅适用于Rails并在原始字符串中带有下划线时会出错,另一个仅适用于ruby 1.9,第三个则始终存在其特殊字符的潜在错误。我真的很喜欢@Alex Kliuchnikau的零宽断言答案,但是OP需要ruby 1.8,它不支持后顾。有一个答案仅使用零宽度前瞻,并且在1.8和1.9中都可以正常工作,它使用String#scan而不是#split
str.scan /.*?[a-z](?=[A-Z]|$)/
=> ["Hello", "World How are", "You I Am", "Fine"]

3
+1 意味着扫描前瞻的解决方案比我的更安全、更快、更短,也更好。 :) - joelparkerhenderson

-1

我认为这个会为你完成任务

str.underscore.split(/_/).each do |s| 
s.capitalize! 
end

3
未来的访问者请注意:这将适用于Rails,而对于纯Ruby代码将无效,因为“underscore”是Rails特有的方法。 - Aliaksei Kliuchnikau
1
未来注意事项:仅当原始文本中没有下划线时,此方法才有效。 - joelparkerhenderson
注意未来:在我的情况下,我一直在使用Rails,并且我处理的字符串不包含“_”,但是@joelparkerhenderson和@Alex提出的问题绝对是合理的,在使用underscore函数之前必须考虑。再次感谢@joel和@Alex。 - Nadeem Yasin
1
@nadeem-yasin,你接受的这个答案不太好,既存在特殊字符错误,又需要Rails库。 - dbenhur
1
我同意 dbenhur 的观点;他的扫描前瞻比这个解决方案和我的提议更短、更快、更安全。在我看来,你应该改用接受 dbenhur 的方案。 - joelparkerhenderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接