`
RednaxelaFX
  • 浏览: 3019175 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

切分字符串,然后把数组逆序的小脚本

阅读更多
刚才正无聊,在JavaEye的问答区Ruby分类里看到了这样一问:
http://www.iteye.com/problems/3
tianshi0253 写道
从键盘输入一组数据,如:“测试,JAVAEYE!”,输出的结果为:“!JAVAEYE,试测”。
并且把它们存储到一个TXT文本中。


这简单的功能要求也挺有趣的,就尝试了一下。
基本思路是先使用String#split,然后用Array#reverse,最后用File.open和puts做输出。所以关键的地方就是要传给String#split的正则表达式参数了。

先忽略中文和全角字符,假设我们处理的都是ASCII字符。然后,那题目看来是要把某些字符看作分隔符来讲字符串分割开来,但同时要求分隔符也被保留。没有明确要求空白字符如何处理,这里假设空白字符在目标字符串中被忽略。

我们知道,给String#split的参数里的正则表达式所能匹配的子串会被“吃掉”,所以为了匹配分隔符而又不让它们被“吃掉”,我们就需要“零长度匹配”,或者叫“环视”(lookaround)。
同时使用正向和逆向环视(lookahead和lookbehind),我们就能够完成对指定的分隔符的匹配和分隔,同时在目标字符串中保留它们。所以最终的程序会类似这样:
split = ",.!?"              # 可以将别的字符定义为分隔符
file_path = "D:/result.txt" # 可以从别的地方获取输出的文件的路径
File.open(file_path, "w") do |file|
  file.puts gets.chomp.split(/\s*(?:(?<=[#{split}])|(?=[#{split}]))\s*/).reverse.join("")
end

这样,当我们执行这个程序,并且在命令行输入下面的字符串时:
Hello, JavaEye!

在D:\result.txt里我们就会得到:
!JavaEye,Hello

差不多了吧?注意到空格被去掉了(基于上面的假设)

来仔细看看那个正则表达式(先将split带入进去):
/\s*(?:(?<=[#{split}])|(?=[#{split}]))\s*/

一头一尾都是匹配任意个数的空白字符:\s*
中间是一个非捕获型分组(? ... )
这个分组内有两个选择,前一个是逆向环视,用于匹配左边有分隔符的情况:(?<=[,.!?])
后一个是正向环视,用于匹配右边有分隔符的情况:(?=[,.!?])

这样就大致的解决了那个问题,只是……

(又有“只是”了)嗯,用Ruby 1.8.x来执行上面的代码是行不通的。因为Ruby采用的正则表达式引擎是自己实现的,而不是PCRE或者Perl自身用的那个,不支持逆向环视。
幸好,在Ruby 1.9.0里,正则表达式的引擎换成了Oniguruma(鬼車),总算支持了逆向环视。前面的代码的运行就是在Ruby 1.9.0-0上测试的。

但是……
还有一个重要的问题暂时被忽略了:中文和全角符号的支持。
如果是以UNICODE为内部编码表示的语言,那这根本不是问题;所以像是C#啊Java之类的都不会碰到什么问题。但是Ruby直到1.8.6为止对UTF-8/UTF-16/Shift-JIS以外的编码的支持都挺糟糕的。Windows下的控制台一般是设置到操作系统的默认locale,在简体中文Windows上就是GBK。这样输入到Ruby解释器里的中文字符串就可能有问题

假如把上面代码中的分隔符设置为",!"(注意到是全角字符),然后保存为UTF-8的源码文件,那么运行的时候会出错:
split.rb:4:in `split': incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string) (ArgumentError)
        from split.rb:4:in `block in <main>'
        from split.rb:3:in `open'
        from split.rb:3:in `<main>'

假如还是保存为ANSI(简体中文Windows上也就是GBK),那么运行的结果就不太对:
。JavaEye测试


我也不知道有什么好办法来解决这个问题……GUI程序的话说不定还有点办法,控制台程序真是一点办法都没有(总不能要求用户为了这么个小程序去调整控制台编码吧 = =)
平时自己写的小程序多半都只用英文,就避开了这个问题。但是要是写给别人用,而又非要用中文的话,那我还真的不知道怎么办好了。Sigh。
分享到:
评论
4 楼 RednaxelaFX 2008-05-19  
lwwin 写道
直接想到的是:
#include <string.h> 
#include <stdio.h> 
#include <locale.h> 
void main(void){ 
    wchar_t* str=L"测试,JAVAEYE!"; 
    setlocale(LC_ALL,""); 
    fwprintf(stderr,L"%s",_wcsrev(str)); 
}

这样的话只是把字符串的内容整个反转了过来,而不是按照token来反转,很明显跟原本的问题给出的例子不相符……
那帖里的回复多半都是这样的,要是只要把字符串内容反转过来的话那在Ruby里一样是简单,用String#reverse就完事了 = =
引用
--------------------------------------------------------- String#reverse
     str.reverse   => new_str
------------------------------------------------------------------------
     Returns a new string with the characters from _str_ in reverse
     order.

        "stressed".reverse   #=> "desserts"
3 楼 tianshi0253 2008-05-17  
看到楼主这么写,很感动呢。
呵呵,我是一个小鸟, 也是新手呢。呵呵
看不懂呢。不过感觉你写的很好呢。呵呵
谢谢了。
收藏一下了。
2 楼 lwwin 2008-05-16  
控制台的版本……支持32个U……
#include <string.h>
#include <stdio.h>
#include <locale.h>
void main(void){
    wchar_t str[32];
    setlocale(LC_ALL,"");
    wscanf(L"%s",str);
    fwprintf(stderr,L"%s",_wcsrev(str));
}
1 楼 lwwin 2008-05-16  
直接想到的是:
#include <string.h>
#include <stdio.h>
#include <locale.h>
void main(void){
    wchar_t* str=L"测试,JAVAEYE!";
    setlocale(LC_ALL,"");
    fwprintf(stderr,L"%s",_wcsrev(str));
}
不知道为啥不用locale就不行显示中文,细节很深奥嘛-v-+不愧是FX大了~

相关推荐

Global site tag (gtag.js) - Google Analytics