ruby 字符串经常使用方法学习

引用连接:http://www.blogjava.net/nkjava/archive/2010/01/03/308088.htmlhtml

 

1,切片:silce, [ ]-----------------[ ]是silce的别名,因此二者是彻底相同的
操做1:断定字符串中是否含有字串/子模式
string[substring]
string[/pattern/]
string[/pattern/, position] #position以后的子串中是否含有/pattern/
若是存在返回子串/子模式串,不然返回nil
“hello world"["hello"]==="hello"
"hello world"[/.*lo/]==="hello"
"hello world"[/en/]===nil

操做2:使用索引截取子串
string[position] #注意返回的是ASCII码而不是字符
string[start, length]
string[start..end]
string[start...end]

2,比较:
== #比较字符串是否相等
eql? #??好像没有区别
<=> #用来比较字符串的大小,大于返回 1,小于返回 -1, 不然返回0

3,字符串的运算
downcase #改变字符串为所有小写
upcase #改变字符串为所有大写
swapcase#反写
capitalize #改变字符串为首字母大写
* #重复字符串
insert num, string #在num位置插入串string(insert没有!,由于insert会直接改变原串)
delete(!) string1 (,string2) #删除string1交string2的字符
gsub find, replace #将串中的find,替换为replace. find能够是正则表达式,replace很显然不能够。注意:是全部相同的都替换,至关与sed中的s/pattern/string/g
replace string #将字符串替换为string, 这是对象没有变,只是其中的内容发生了变化。

利用切片来改变字符串(silce!, [ ]=)
"hello"["ello"]= "w" # "hw"
"hello"[1]="wan" # "hwanllo"
“hello"[1..3]= "wrd" #"hwrdo"
"hello"[1...3]= "wr" #"hwrlo"
"hello"[1,3]="wrd" #"hwrdo"
"hello"[/el/]= "wr" #"hwrlo"

chomp(!) 用来摘除字符串末尾的换行符(若是不是换行符返回空)#注意只能是换行符,空格都不行
chop(!)用来摘除字符串末尾的最后一个字符
reverse(!)首尾倒置
split(/pattern/)将字符串分割成数组,分隔符是/pattern/(注意带!的方法不能用来改变类,因此split没有!)


字符串长度
string.length
string.size

字符串对齐
string.ljust num, char #用char来填充string,不足num的部分。注意左对齐是右填充。若是字符串长度比char大,忽略
string.rjust num, char
string.center num, char

string.lstrip #trim字符串,去除左边空格
string.rstrip
string.strip #去掉字符串的先后空格
..........那么如何去掉全部的空格呢? 很简单,使用gsub,进行替换

string.next/succ #string+1 不是+1这么简单。"a".next == "zz"
string1.upto(stringn) #string1, string2 ....stringn

字符串遍历:
string.each #分割不一样项的必须是\n "hello\nworld".each {|e| puts e << ","}===
hello,
world,
"hello world".each{|e| puts e << ","}===
hello world,
string.each_byte #以字节为单位遍历



求字串的索引位置
string.index substring #正则表达式也能够

正则表达式专用
string.grep /pattern/ #若是不是正则表达式搜索不到任何东西,若是是且匹配返回包含整个字符串的一个数组
string =~ /pattern/ #pattern第一次出现的位置
string !~ /pattern/ #若是没有找到/pattern返回true(注意!)


uby很强大,但是相关资料少而不详细。本文是我的学习总结,测试环境是windows xp sp3 + NetBeans6.7.1(JRuby 1.2.0),主要结论来自于互联网、"Programming Ruby"2e、对于源代码的分析和实测代码。java

双引号字符串和单引号字符串

都能表示字符串对象,区别在于双引号字符串可以支持更多的转义字符。下面的代码在字符串中增长了'符号。
str=‘he'lo’
puts str
显示结果为he'lo。

单引号仅支持\\ => \ 和 \' => '

下表是ruby中双引号字符串支持的转义字符:c++

分界符


    全部不是字母或者数字的单字节字符均可以成为String的分界符。注意,一般他们都是成对出现的,好比<和>,!和!,{和}等。正则表达式

构造字符串字面量

方法一:
最简单的使用单引号或者双引号括起来的字符串,好比"hello"。

方法二:
使用%q配合分界符,%q表明单引号
str=%q!he\lo!

方法三:
使用%Q配合分界符,%Q表明双引号
str=%Q{he\lo}

方法四:
here document构建字符串,该方法比较适合用于多行字符串的建立。由<<和边界字符串做为开头,由边界字符串做为结尾,好比下列代码:
str = <<END_OF_STRING1
  We are here now,
  where are you?
END_OF_STRING1
puts str
输出结果为:
  We are here now,
  where are you?

较为复杂的是容许多个边界字符串对出现。
str = <<END_OF_STRING1,<<END_OF_STRING2
  We are here now,
  where are you?
END_OF_STRING1
  I will leave now,
  would you like to go with me?
END_OF_STRING2

puts str
输出结果为:
  We are here now,
  where are you?
  I will leave now,
  would you like to go with me?算法

字面量与copy-on-write技术


    在Java中,若是两个String对象a和b的值都是"abcdef",以下:
String a="abcdef";
String b="abcdef";
那 么,JVM只会建立一个常量对象"abcdef",让a和b都指向它。可是在ruby中,采用了智能指针(熟悉c++的朋友清楚)的一个高级技术 copy-on-write,一开始也是共享同一个字符常量,可是一旦以后某个对象(好比b对象)进行了修改操做,则"abcdef"将产生一个副本,b 的修改操做在这个副本上进行。
    更详细的讨论请参考http://developer.51cto.com/art/200811/98630.htm。windows

和Java的一些其余区别

    Java的String每次执行修改操做,都不会改变自身,而是建立一个新的String对象,而Ruby每次的修改操做都会修改自身。api

计算长度

puts "hello".length
    该句输出5,是字符个数,不要和C函数搞混,C函数常常用0结束字符串,所以长度常常为实际字符个数+1,Ruby中没有这个习惯。数组

查找

从左向右查找第一个

    index方法有三种重载,分别是:
str.index(substring [, offset]) => fixnum or nil
str.index(fixnum [, offset]) => fixnum or nil
str.index(regexp [, offset]) => fixnum or nil

    第二个参数offset是可选参数,不用的话则从索引0的字符开始查找。
puts "hello".index("el") 输出为1 ,注意这里的'el'也能够。也能够只查一个字符比,如puts "hello".index(101) 输出为1,这时候第一个参数为'e'的二进制码。
也可使用正则表达式进行查找,好比puts "hello".index(/[az]/) 输出为nil,由于"hello"不包含a或者z。[]是正则表达式的运算符,表明里面的a和z有一个找到便可。
puts "hello".index(/lo/) 这个没有[]符号,所以是查找子字符串lo,结果为3.
    我我的以为尽可能熟练使用正则表达式查找是最好的选择,既能够完成简单查找,也能够完成难度查找。不过须要付出很多努力去学习。
    下面这个例子puts "hello".index('o', -1) 证实了第二个参数能够为负数,虽然这没有什么意义,由于功能和为0等价。
    若是查找不到,返回nil。ruby

逆向查找(从左向右查找最后一个仍是从右向左查找第一个)

str.rindex(substring [, fixnum]) => fixnum or nil
str.rindex(fixnum [, fixnum]) => fixnum or nil
str.rindex(regexp [, fixnum]) => fixnum or nil
   
    第一个参数和index相同,第二个参数是可选,若是不用则默认为字符串尾部。若是为0呢?则从第一个字符开始向右查找。若是为负数呢?这时候很奇怪,居 然能查到。经过看C的实现代码,发现当fixnum<0时,会执行这个运算:fixnum+=substring.length,而后就能找到。逻 辑上能够理解为当fixnum<0时,将从最右边开始向左移动abs(fixnum)-1个位置,并做为最后查找范围,而后开始从左至右进行查找。 字符串最右边的字符的位置被-1表明。
下面两行代码结果都是nil:
puts "hlloe".rindex('e', -2)
puts "hlloe".rindex('e', 3)

下面两行代码结果都是1:
puts "hello".rindex('e', -2)
puts "hello".rindex('e', 3)

    注意,以上的代码理解是我我的观察代码后的猜想,由于我还不会调试运行ruby的C代码,因此不必定正确。代码摘录以下:(代码是ruby网站公布的C代 码,可是我所用的平台其实NetBeans6.7.1,所以真正代码应该是Java实现的JRuby1.2.0,这里的C代码仅供参考)
static VALUE
rb_str_rindex_m(argc, argv, str)
    int argc;
    VALUE *argv;
    VALUE str;
{
    VALUE sub;
    VALUE position;
    long pos;

    if (rb_scan_args(argc, argv, "11", ⊂, &position) == 2) {
        pos = NUM2LONG(position);
        if (pos < 0) {
            pos += RSTRING(str)->len;
            if (pos < 0) {
                if (TYPE(sub) == T_REGEXP) {
                    rb_backref_set(Qnil);
                }
                return Qnil;
            }
        }
        if (pos > RSTRING(str)->len) pos = RSTRING(str)->len;
    }
    else {
        pos = RSTRING(str)->len;
    }

    switch (TYPE(sub)) {
      case T_REGEXP:
        if (RREGEXP(sub)->len) {
            pos = rb_reg_adjust_startpos(sub, str, pos, 1);
            pos = rb_reg_search(sub, str, pos, 1);
        }
        if (pos >= 0) return LONG2NUM(pos);
        break;

      case T_STRING:
        pos = rb_str_rindex(str, sub, pos);
        if (pos >= 0) return LONG2NUM(pos);
        break;

      case T_FIXNUM:
      {
          int c = FIX2INT(sub);
          unsigned char *p = (unsigned char*)RSTRING(str)->ptr + pos;
          unsigned char *pbeg = (unsigned char*)RSTRING(str)->ptr;

          if (pos == RSTRING(str)->len) {
              if (pos == 0) return Qnil;
              --p;
          }
          while (pbeg <= p) {
              if (*p == c) return LONG2NUM((char*)p - RSTRING(str)->ptr);
              p--;
          }
          return Qnil;
      }



一般咱们理解为从右边开始查找,可是注释却代表是从左向右查找,并返回最后一个找到的目标的位置。究竟内幕如何,只能看代码。
01161 static long
01162 rb_str_rindex (str, sub, pos)
01163 VALUE str, sub;
01164 long pos;
01165 {
01166 long len = RSTRING (sub)->len;
01167 char *s, *sbeg, *t;
01168
01169 /* substring longer than string */
01170 if (RSTRING (str)->len < len) return -1;
01171 if (RSTRING (str)->len - pos < len) {
01172 pos = RSTRING (str)->len - len;
01173 }
01174 sbeg = RSTRING (str)->ptr;
01175 s = RSTRING (str)->ptr + pos;
01176 t = RSTRING (sub)->ptr;
01177 if (len) {
01178 while (sbeg <= s) {
01179 if ( rb_memcmp (s, t, len) == 0) {
01180 return s - RSTRING (str)->ptr;
01181 }
01182 s--;
01183 }
01184 return -1;
01185 }
01186 else {
01187 return pos;
01188 }
01189 }

    经过看代码,发现s--;所以,是从右向左进行匹配,找到的第一个就返回。写注释的人应该枪毙!虽然看上去意思同样,可是算法的时间复杂度大不同。从左到右的查找老是O(n),而从右到左的最坏事件复杂度才是O(n)。
函数

大小写不区分查找

    puts "hello".upcase.index("H"),利用downcase或者upcase所有转换成小写或者大写,而后再查找。

正则表达式匹配查找

operator =~ 将返回匹配的模式开始位置,若是没有找到则返回nil。
puts "abcde789" =~ /d/
输出5.

提取子字符串

str="hello"
puts str[0,2]
第一个参数是子字符串首字母的Index,第二个是长度(不能为负数)。
结果为he。
第一个参数能够为负数,会把最右边的字符做为-1,而后向左增长-1的方式查找起始位置,好比:
str="hello"
puts str[-2,2]
输出为lo,这种状况咱们在rindex方法中已经看到过了。

也可使用正则表达式进行提取,这真的很强大。
str="hello"
puts str[/h..l/]
输出为hell。

符号.表明一个字符,两个.表明两个字符。两个/里面的内容就是正则表达式。.*表明能够有无数个字符,好比
str="hello"
puts str[/h.*o/]
输出为hello。

字符计数

String#count用来计算咱们参数中给出的字符集中字符出现的总次数,好比最简单的状况:
str = "hello,world"
puts str.count "w"
 “w" 参数表明的是一个字符结合,里面只有一个字符w,count方法计算出w出如今"hello,world"的次数是1,所以输出为1。
下面咱们的参数里面包含了三个字符:
str = "hello,world"
puts str.count "wld"
输出为5,w出现1次,l出现3次,d出现1次,正好5次。

也能够传递多个参数,每一个参数表明一个字符集合,这时候这些字符集合的交集做为count计算的条件:
str = "hello,world"
puts str.count "lo","o"
输出为2。
str = "hello,world"
puts str.count "lo","o"," "
输出为0,由于三个集合的交集为空,因此计算结果为0.

注意,若是参数^o,表明o出现的次数不计算。

删除末尾分隔符

String#chomp方法有一个字符串参数,指定了要在末尾删除的子字符串。若是不用这个参数,则会将字符串末尾的n,r和rn删除(若是有的话)。

压缩重复字符

String#squeeze方法若是不用参数,则会将字符串中的任何连续重复字符变成单一字符,以下:
str = "helllloo"
puts str.squeeze
输出:helo。
若是传递字符串参数,含义同count方法的参数同样,表明了一个字符集合,则将符合条件(1,在字符集合中出现;2,在字符串中连续出现)的子字符串压缩成的单一字符
实例代码以下:
str = "helllloo"
puts str.squeeze('l')
puts str.squeeze('a-l')
puts str.squeeze('lo')
输出为:
heloo
heloo
helo

    参数也能够用a-z方式表示在某个字符集合区间内。

一个很经常使用的功能是利用squeeze(" ")对字符串内重复的空白字符进行压缩。

字符串删除

delete方法

能够接收多个参数,每一个参数表明一个字符集合,相似count方法。若是有多个参数,取交集,而后从字符串中删除全部出如今交集中的字符。
"hello".delete "l","lo" #=> "heo"
"hello".delete "lo" #=> "he"
"hello".delete "aeiou", "^e" #=> "hell"
"hello".delete "ej-m" #=> "ho"

利用sub和gsub

参见后面的sub用法,使用''进行替换便可。

字符串拆分

String#split接收两个参数,第一个参数老是被做为间隔符来拆分字符串,而且不会出如今结果中。
第一个参数若是是正则表达式的话,若是为空,则每一个字符都被拆开,返回一个字符数组。例子代码以下:
str = "hello"
puts str.split(//)
输出为:
h
e
l
l
o

    若是正则表达式不为空,则根据匹配的状况进行拆分。例子代码以下:
str = "hello"
puts str.split(/h/)
结果为:

ello

拆分红了两个数组,第一个为"",第二个为ello,用h进行拆分的。
第一个参数的另外一种用法很简单,只是一个字符串,用于做为间隔符进行拆分,就不举例子了。我更倾向于使用强大的正则表达式。

第二个参数是一个整数,用于对拆分的结果数组的元素个数进行限制,这个功能有多大用处,我如今到没有体会,通常状况下不用便可。

大小写转换

    如前面出现的,利用downcase或者upcase方法便可。

数组操做

使用[],里面填上Index,就能够获取第Index个元素。

和数值类型的相互转换


获取单字节字符的二进制码
puts ?e
?运算符用于中文是非法的。

字符串迭代

Ruby迭代器的设计不在这里讨论,我会专门有一篇文章描述。

each_char

迭代每一个字符,下面是示例代码:
require 'jcode' #NetBeans6.7.1和JRuby1.2.0须要,不然下面代码找不到方法
"hello".each_char(){ |c| print c,' ' } #()能够不写

|c| 表明字符串中的当前字符。

each

迭代每一个子字符串,若是不传递seperator参数,则默认用n做为seperator。
"hellonworld".each { |c| puts c }
输出为:
hello
world

若是传递了有效的字符串做为seperator参数,那么就以这个seperator代替n进行子字符串的迭代:
"hellonworld".each('l') { |s| p s }
输出为:
"hel"
"l"
"onworl"
"d"

each_byte

用法和each_char相似,不过迭代的对象是char,所以输出的是二进制数值。
"hellonworld".each_byte { |s| print s," " }
输出:
104 101 108 108 111 10 119 111 114 108 100

each_line

用法和前面相同,只是用换行符分割子字符串进行迭代:
"hellonworld".each_line do |s|
  print s
end
    注意,这是另外一种写法,用do/end替换了{/}对。
输出为:
hello
world
只因此输出为两行,是由于第一个子字符串是"hellon"输出后自动换行。

字符串拼接

使用operator +操做

str1="hello,"
str2="world"
str3=str1+str2
puts str3
输出为hello,world

使用operator <<操做

str1="hello,"
str2="world"
str1<
puts str1
输出为hello,world

concat方法

concat方法能够在字符串后面加上一个二进制值为[0,255]的字符,用法以下:
str1="hello,world"
str1.concat(33)#33是!的二进制值
puts str1
输出为hello,world!

concat也能够接一个object,好比另外一个String对象

是否为空

String#empty? 方法 若是为空返回true,不然返回false

字符串比较

operator<=>操做

str1<=>str2
若是str1小于str2,返回-1;
若是str1等于str2,返回0;
若是str1大于str2,返回1。

官方注释写反了。

operator==操做

两个比较对象必须都为String,不然返回false;
若是都是String对象,则调用operator <=> 操做符进行比较,比较结果为0时,返回true,不然返回false

字符串替换

replace方法

和operator = 功能相同,字符串内容的彻底替换,没什么做用。

sub方法

str.sub(pattern, replacement) => new_str
str.sub(pattern) {|match| block } => new_str


在str副本上将找到的第一个匹配字符(串)用replacement替换,并返回。好比:
puts "abcde789".sub(/d/, "000")
输出为:abcde00089

第二种重载形式容许执行一段代码,好比:
puts "abcde789".sub(/d/){|c| 'a'}
找到的字符用|c|表示,能够替换成a字符
输出为:abcdea89

gsub方法

和sub的区别在于全部匹配的地方都会被替换,而不仅是第一个。

相关文章
相关标签/搜索