大漠駝鈴

          置身浩瀚的沙漠,方向最為重要,希望此blog能向大漠駝鈴一樣,給我方向和指引。
          Java,Php,Shell,Python,服務(wù)器運(yùn)維,大數(shù)據(jù),SEO, 網(wǎng)站開發(fā)、運(yùn)維,云服務(wù)技術(shù)支持,IM服務(wù)供應(yīng)商, FreeSwitch搭建,技術(shù)支持等. 技術(shù)討論QQ群:428622099
          隨筆 - 238, 文章 - 3, 評(píng)論 - 117, 引用 - 0
          數(shù)據(jù)加載中……

          Ruby學(xué)習(xí)1-字符串

          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? #??好像沒有區(qū)別
          <=> #用來比較字符串的大小,大于返回 1,小于返回 -1, 否則返回0

          3,字符串的運(yùn)算
          downcase #改變字符串為全部小寫
          upcase #改變字符串為全部大寫
          swapcase#反寫
          capitalize #改變字符串為首字母大寫
          * #重復(fù)字符串
          insert num, string #在num位置插入串string(insert沒有!,因?yàn)閕nsert會(huì)直接改變?cè)?br /> delete(!) string1 (,string2) #刪除string1交string2的字符
          gsub find, replace #將串中的find,替換為replace. find可以是正則表達(dá)式,replace很顯然不可以。注意:是所有相同的都替換,相當(dāng)與sed中的s/pattern/string/g
          replace string #將字符串替換為string, 這是對(duì)象沒有變,只是其中的內(nèi)容發(fā)生了變化。

          利用切片來改變字符串(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(!)用來摘除字符串末尾的最后一個(gè)字符
          reverse(!)首尾倒置
          split(/pattern/)將字符串分割成數(shù)組,分隔符是/pattern/(注意帶!的方法不能用來改變類,所以split沒有!)


          字符串長(zhǎng)度
          string.length
          string.size

          字符串對(duì)齊
          string.ljust num, char #用char來填充string,不足num的部分。注意左對(duì)齊是右填充。如果字符串長(zhǎng)度比char大,忽略
          string.rjust num, char
          string.center num, char

          string.lstring #trim字符串,去除左邊空格
          string.rstring
          string.strip
          ..........那么如何去掉所有的空格呢? 很簡(jiǎn)單,使用gsub,進(jìn)行替換

          string.next/succ #string+1 不是+1這么簡(jiǎn)單。"a".next == "zz"
          string1.upto(stringn) #string1, string2 ....stringn

          字符串遍歷:
          string.each #分割不同項(xiàng)的必須是\n "hello\nworld".each {|e| puts e << ","}===
          hello,
          world,
          "hello world".each{|e| puts e << ","}===
          hello world,
          string.each_byte #以字節(jié)為單位遍歷



          求字串的索引位置
          string.index substring #正則表達(dá)式也可以

          正則表達(dá)式專用
          string.grep /pattern/ #如果不是正則表達(dá)式搜索不到任何東西,如果是且匹配返回包含整個(gè)字符串的一個(gè)數(shù)組
          string =~ /pattern/ #pattern第一次出現(xiàn)的位置
          string !~ /pattern/ #如果沒有找到/pattern返回true(注意!)


          uby很強(qiáng)大,可是相關(guān)資料少而不詳細(xì)。本文是個(gè)人學(xué)習(xí)總結(jié),測(cè)試環(huán)境是windows xp sp3 + NetBeans6.7.1(JRuby 1.2.0),主要結(jié)論來自于互聯(lián)網(wǎng)、"Programming Ruby"2e、對(duì)于源代碼的分析和實(shí)測(cè)代碼。

          雙引號(hào)字符串和單引號(hào)字符串

          都能表示字符串對(duì)象,區(qū)別在于雙引號(hào)字符串能夠支持更多的轉(zhuǎn)義字符。下面的代碼在字符串中增加了'符號(hào)。
          str=‘he'lo’
          puts str
          顯示結(jié)果為he'lo。

          單引號(hào)僅支持\\ => \ 和 \' => '

          下表是ruby中雙引號(hào)字符串支持的轉(zhuǎn)義字符:

          分界符


              所有不是字母或者數(shù)字的單字節(jié)字符都可以成為String的分界符。注意,通常他們都是成對(duì)出現(xiàn)的,比如<和>,!和!,{和}等。

          構(gòu)造字符串字面量

          方法一:
          最簡(jiǎn)單的使用單引號(hào)或者雙引號(hào)括起來的字符串,比如"hello"。

          方法二:
          使用%q配合分界符,%q代表單引號(hào)
          str=%q!he\lo!

          方法三:
          使用%Q配合分界符,%Q代表雙引號(hào)
          str=%Q{he\lo}

          方法四:
          here document構(gòu)建字符串,該方法比較適合用于多行字符串的創(chuàng)建。由<<和邊界字符串作為開頭,由邊界字符串作為結(jié)尾,比如下列代碼:
          str = <<END_OF_STRING1
            We are here now,
            where are you?
          END_OF_STRING1
          puts str
          輸出結(jié)果為:
            We are here now,
            where are you?

          較為復(fù)雜的是允許多個(gè)邊界字符串對(duì)出現(xiàn)。
          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
          輸出結(jié)果為:
            We are here now,
            where are you?
            I will leave now,
            would you like to go with me?

          字面量與copy-on-write技術(shù)


              在Java中,如果兩個(gè)String對(duì)象a和b的值都是"abcdef",如下:
          String a="abcdef";
          String b="abcdef";
          那 么,JVM只會(huì)創(chuàng)建一個(gè)常量對(duì)象"abcdef",讓a和b都指向它。但是在ruby中,采用了智能指針(熟悉c++的朋友清楚)的一個(gè)高級(jí)技術(shù) copy-on-write,一開始也是共享同一個(gè)字符常量,但是一旦之后某個(gè)對(duì)象(比如b對(duì)象)進(jìn)行了修改操作,則"abcdef"將產(chǎn)生一個(gè)副本,b 的修改操作在這個(gè)副本上進(jìn)行。
              更詳細(xì)的討論請(qǐng)參考http://developer.51cto.com/art/200811/98630.htm。

          和Java的一些其他區(qū)別

              Java的String每次執(zhí)行修改操作,都不會(huì)改變自身,而是創(chuàng)建一個(gè)新的String對(duì)象,而Ruby每次的修改操作都會(huì)修改自身。

          計(jì)算長(zhǎng)度

          puts "hello".length
              該句輸出5,是字符個(gè)數(shù),不要和C函數(shù)搞混,C函數(shù)經(jīng)常用0結(jié)束字符串,因此長(zhǎng)度經(jīng)常為實(shí)際字符個(gè)數(shù)+1,Ruby中沒有這個(gè)習(xí)慣。

          查找

          從左向右查找第一個(gè)

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

              第二個(gè)參數(shù)offset是可選參數(shù),不用的話則從索引0的字符開始查找。
          puts "hello".index("el") 輸出為1 ,注意這里的'el'也可以。也可以只查一個(gè)字符比,如puts "hello".index(101) 輸出為1,這時(shí)候第一個(gè)參數(shù)為'e'的二進(jìn)制碼。
          也可以使用正則表達(dá)式進(jìn)行查找,比如puts "hello".index(/[az]/) 輸出為nil,因?yàn)?hello"不包含a或者z。[]是正則表達(dá)式的運(yùn)算符,代表里面的a和z有一個(gè)找到即可。
          puts "hello".index(/lo/) 這個(gè)沒有[]符號(hào),因此是查找子字符串lo,結(jié)果為3.
              我個(gè)人覺得盡量熟練使用正則表達(dá)式查找是最好的選擇,既可以完成簡(jiǎn)單查找,也可以完成難度查找。不過需要付出不少努力去學(xué)習(xí)。
              下面這個(gè)例子puts "hello".index('o', -1) 證明了第二個(gè)參數(shù)可以為負(fù)數(shù),雖然這沒有什么意義,因?yàn)楣δ芎蜑?等價(jià)。
              如果查找不到,返回nil。

          逆向查找(從左向右查找最后一個(gè)還是從右向左查找第一個(gè))

          str.rindex(substring [, fixnum]) => fixnum or nil
          str.rindex(fixnum [, fixnum]) => fixnum or nil
          str.rindex(regexp [, fixnum]) => fixnum or nil
             
              第一個(gè)參數(shù)和index相同,第二個(gè)參數(shù)是可選,如果不用則默認(rèn)為字符串尾部。如果為0呢?則從第一個(gè)字符開始向右查找。如果為負(fù)數(shù)呢?這時(shí)候很奇怪,居 然能查到。通過看C的實(shí)現(xiàn)代碼,發(fā)現(xiàn)當(dāng)fixnum<0時(shí),會(huì)執(zhí)行這個(gè)運(yùn)算:fixnum+=substring.length,然后就能找到。邏 輯上可以理解為當(dāng)fixnum<0時(shí),將從最右邊開始向左移動(dòng)abs(fixnum)-1個(gè)位置,并作為最后查找范圍,然后開始從左至右進(jìn)行查找。 字符串最右邊的字符的位置被-1代表。
          下面兩行代碼結(jié)果都是nil:
          puts "hlloe".rindex('e', -2)
          puts "hlloe".rindex('e', 3)

          下面兩行代碼結(jié)果都是1:
          puts "hello".rindex('e', -2)
          puts "hello".rindex('e', 3)

              注意,以上的代碼理解是我個(gè)人觀察代碼后的猜測(cè),因?yàn)槲疫€不會(huì)調(diào)試運(yùn)行ruby的C代碼,所以不一定正確。代碼摘錄如下:(代碼是ruby網(wǎng)站公布的C代 碼,但是我所用的平臺(tái)其實(shí)NetBeans6.7.1,因此真正代碼應(yīng)該是Java實(shí)現(xiàn)的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;
                }



          通常我們理解為從右邊開始查找,但是注釋卻表明是從左向右查找,并返回最后一個(gè)找到的目標(biāo)的位置。究竟內(nèi)幕如何,只能看代碼。
          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 }

              通過看代碼,發(fā)現(xiàn)s--;因此,是從右向左進(jìn)行匹配,找到的第一個(gè)就返回。寫注釋的人應(yīng)該槍斃!雖然看上去意思一樣,但是算法的時(shí)間復(fù)雜度大不一樣。從左到右的查找總是O(n),而從右到左的最壞事件復(fù)雜度才是O(n)。

          大小寫不區(qū)分查找

              puts "hello".upcase.index("H"),利用downcase或者upcase全部轉(zhuǎn)換成小寫或者大寫,然后再查找。

          正則表達(dá)式匹配查找

          operator =~ 將返回匹配的模式開始位置,如果沒有找到則返回nil。
          puts "abcde789" =~ /d/
          輸出5.

          提取子字符串

          str="hello"
          puts str[0,2]
          第一個(gè)參數(shù)是子字符串首字母的Index,第二個(gè)是長(zhǎng)度(不能為負(fù)數(shù))。
          結(jié)果為he。
          第一個(gè)參數(shù)可以為負(fù)數(shù),會(huì)把最右邊的字符作為-1,然后向左增加-1的方式查找起始位置,比如:
          str="hello"
          puts str[-2,2]
          輸出為lo,這種情況我們?cè)趓index方法中已經(jīng)看到過了。

          也可以使用正則表達(dá)式進(jìn)行提取,這真的很強(qiáng)大。
          str="hello"
          puts str[/h..l/]
          輸出為hell。

          符號(hào).代表一個(gè)字符,兩個(gè).代表兩個(gè)字符。兩個(gè)/里面的內(nèi)容就是正則表達(dá)式。.*代表可以有無數(shù)個(gè)字符,比如
          str="hello"
          puts str[/h.*o/]
          輸出為hello。

          字符計(jì)數(shù)

          String#count用來計(jì)算我們參數(shù)中給出的字符集中字符出現(xiàn)的總次數(shù),比如最簡(jiǎn)單的情況:
          str = "hello,world"
          puts str.count "w"
           “w" 參數(shù)代表的是一個(gè)字符結(jié)合,里面只有一個(gè)字符w,count方法計(jì)算出w出現(xiàn)在"hello,world"的次數(shù)是1,因此輸出為1。
          下面我們的參數(shù)里面包含了三個(gè)字符:
          str = "hello,world"
          puts str.count "wld"
          輸出為5,w出現(xiàn)1次,l出現(xiàn)3次,d出現(xiàn)1次,正好5次。

          也可以傳遞多個(gè)參數(shù),每個(gè)參數(shù)代表一個(gè)字符集合,這時(shí)候這些字符集合的交集作為count計(jì)算的條件:
          str = "hello,world"
          puts str.count "lo","o"
          輸出為2。
          str = "hello,world"
          puts str.count "lo","o"," "
          輸出為0,因?yàn)槿齻€(gè)集合的交集為空,所以計(jì)算結(jié)果為0.

          注意,如果參數(shù)^o,代表o出現(xiàn)的次數(shù)不計(jì)算。

          刪除末尾分隔符

          String#chomp方法有一個(gè)字符串參數(shù),指定了要在末尾刪除的子字符串。如果不用這個(gè)參數(shù),則會(huì)將字符串末尾的n,r和rn刪除(如果有的話)。

          壓縮重復(fù)字符

          String#squeeze方法如果不用參數(shù),則會(huì)將字符串中的任何連續(xù)重復(fù)字符變成單一字符,如下:
          str = "helllloo"
          puts str.squeeze
          輸出:helo。
          如果傳遞字符串參數(shù),含義同count方法的參數(shù)一樣,代表了一個(gè)字符集合,則將符合條件(1,在字符集合中出現(xiàn);2,在字符串中連續(xù)出現(xiàn))的子字符串壓縮成的單一字符
          實(shí)例代碼如下:
          str = "helllloo"
          puts str.squeeze('l')
          puts str.squeeze('a-l')
          puts str.squeeze('lo')
          輸出為:
          heloo
          heloo
          helo

              參數(shù)也可以用a-z方式表示在某個(gè)字符集合區(qū)間內(nèi)。

          一個(gè)很常用的功能是利用squeeze(" ")對(duì)字符串內(nèi)重復(fù)的空白字符進(jìn)行壓縮。

          字符串刪除

          delete方法

          可以接收多個(gè)參數(shù),每個(gè)參數(shù)代表一個(gè)字符集合,類似count方法。如果有多個(gè)參數(shù),取交集,然后從字符串中刪除所有出現(xiàn)在交集中的字符。
          "hello".delete "l","lo" #=> "heo"
          "hello".delete "lo" #=> "he"
          "hello".delete "aeiou", "^e" #=> "hell"
          "hello".delete "ej-m" #=> "ho"

          利用sub和gsub

          參見后面的sub用法,使用''進(jìn)行替換即可。

          字符串拆分

          String#split接收兩個(gè)參數(shù),第一個(gè)參數(shù)總是被作為間隔符來拆分字符串,并且不會(huì)出現(xiàn)在結(jié)果中。
          第一個(gè)參數(shù)如果是正則表達(dá)式的話,如果為空,則每個(gè)字符都被拆開,返回一個(gè)字符數(shù)組。例子代碼如下:
          str = "hello"
          puts str.split(//)
          輸出為:
          h
          e
          l
          l
          o

              如果正則表達(dá)式不為空,則根據(jù)匹配的情況進(jìn)行拆分。例子代碼如下:
          str = "hello"
          puts str.split(/h/)
          結(jié)果為:

          ello

          拆分成了兩個(gè)數(shù)組,第一個(gè)為"",第二個(gè)為ello,用h進(jìn)行拆分的。
          第一個(gè)參數(shù)的另一種用法很簡(jiǎn)單,只是一個(gè)字符串,用于作為間隔符進(jìn)行拆分,就不舉例子了。我更傾向于使用強(qiáng)大的正則表達(dá)式。

          第二個(gè)參數(shù)是一個(gè)整數(shù),用于對(duì)拆分的結(jié)果數(shù)組的元素個(gè)數(shù)進(jìn)行限制,這個(gè)功能有多大用處,我現(xiàn)在到?jīng)]有體會(huì),一般情況下不用即可。

          大小寫轉(zhuǎn)換

              如前面出現(xiàn)的,利用downcase或者upcase方法即可。

          數(shù)組操作

          使用[],里面填上Index,就可以獲取第Index個(gè)元素。

          和數(shù)值類型的相互轉(zhuǎn)換


          獲取單字節(jié)字符的二進(jìn)制碼
          puts ?e
          ?運(yùn)算符用于中文是非法的。

          字符串迭代

          Ruby迭代器的設(shè)計(jì)不在這里討論,我會(huì)專門有一篇文章描述。

          each_char

          迭代每個(gè)字符,下面是示例代碼:
          require 'jcode' #NetBeans6.7.1和JRuby1.2.0需要,否則下面代碼找不到方法
          "hello".each_char(){ |c| print c,' ' } #()可以不寫

          |c| 代表字符串中的當(dāng)前字符。

          each

          迭代每個(gè)子字符串,如果不傳遞seperator參數(shù),則默認(rèn)用n作為seperator。
          "hellonworld".each { |c| puts c }
          輸出為:
          hello
          world

          如果傳遞了有效的字符串作為seperator參數(shù),那么就以這個(gè)seperator代替n進(jìn)行子字符串的迭代:
          "hellonworld".each('l') { |s| p s }
          輸出為:
          "hel"
          "l"
          "onworl"
          "d"

          each_byte

          用法和each_char類似,不過迭代的對(duì)象是char,因此輸出的是二進(jìn)制數(shù)值。
          "hellonworld".each_byte { |s| print s," " }
          輸出:
          104 101 108 108 111 10 119 111 114 108 100

          each_line

          用法和前面相同,只是用換行符分割子字符串進(jìn)行迭代:
          "hellonworld".each_line do |s|
            print s
          end
              注意,這是另一種寫法,用do/end替換了{(lán)/}對(duì)。
          輸出為:
          hello
          world
          只所以輸出為兩行,是因?yàn)榈谝粋€(gè)子字符串是"hellon"輸出后自動(dòng)換行。

          字符串拼接

          使用operator +操作

          str1="hello,"
          str2="world"
          str3=str1+str2
          puts str3
          輸出為hello,world

          使用operator <<操作

          str1="hello,"
          str2="world"
          str1<
          puts str1
          輸出為hello,world

          concat方法

          concat方法可以在字符串后面加上一個(gè)二進(jìn)制值為[0,255]的字符,用法如下:
          str1="hello,world"
          str1.concat(33)#33是!的二進(jìn)制值
          puts str1
          輸出為hello,world!

          concat也可以接一個(gè)object,比如另一個(gè)String對(duì)象

          是否為空

          String#empty? 方法 如果為空返回true,否則返回false

          字符串比較

          operator<=>操作

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

          官方注釋寫反了。

          operator==操作

          兩個(gè)比較對(duì)象必須都為String,否則返回false;
          如果都是String對(duì)象,則調(diào)用operator <=> 操作符進(jìn)行比較,比較結(jié)果為0時(shí),返回true,否則返回false

          字符串替換

          replace方法

          和operator = 功能相同,字符串內(nèi)容的完全替換,沒什么作用。

          sub方法

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


          在str副本上將找到的第一個(gè)匹配字符(串)用replacement替換,并返回。比如:
          puts "abcde789".sub(/d/, "000")
          輸出為:abcde00089

          第二種重載形式允許執(zhí)行一段代碼,比如:
          puts "abcde789".sub(/d/){|c| 'a'}
          找到的字符用|c|表示,可以替換成a字符
          輸出為:abcdea89

          gsub方法

          和sub的區(qū)別在于所有匹配的地方都會(huì)被替換,而不只是第一個(gè)。

          posted on 2010-01-03 16:22 草原上的駱駝 閱讀(4066) 評(píng)論(0)  編輯  收藏 所屬分類: Ruby


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 正阳县| 富裕县| 沅陵县| 钟祥市| 海淀区| 南雄市| 绥中县| 溆浦县| 红原县| 彰武县| 嘉善县| 南昌市| 永定县| 大余县| 云霄县| 罗山县| 福清市| 海城市| 宁河县| 南投市| 河东区| 乐至县| 新干县| 剑河县| 嵊州市| 广西| 雅江县| 承德市| 新泰市| 绥芬河市| 女性| 重庆市| 连南| 安庆市| 龙州县| 宜川县| 平安县| 灵武市| 台江县| 屏东县| 宽城|