大漠駝鈴

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

          Ruby學習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? #??好像沒有區別
          <=> #用來比較字符串的大小,大于返回 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.lstring #trim字符串,去除左邊空格
          string.rstring
          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、對于源代碼的分析和實測代碼。

          雙引號字符串和單引號字符串

          都能表示字符串對象,區別在于雙引號字符串能夠支持更多的轉義字符。下面的代碼在字符串中增加了'符號。
          str=‘he'lo’
          puts str
          顯示結果為he'lo。

          單引號僅支持\\ => \ 和 \' => '

          下表是ruby中雙引號字符串支持的轉義字符:

          分界符


              所有不是字母或者數字的單字節字符都可以成為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。

          和Java的一些其他區別

              Java的String每次執行修改操作,都不會改變自身,而是創建一個新的String對象,而Ruby每次的修改操作都會修改自身。

          計算長度

          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。

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

          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的區別在于所有匹配的地方都會被替換,而不只是第一個。

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

          主站蜘蛛池模板: 洞口县| 温州市| 黄石市| 宝坻区| 民乐县| 惠安县| 广平县| 武定县| 梨树县| 永川市| 威宁| 石景山区| 顺昌县| 大名县| 河北区| 东乌| 渭源县| 玉溪市| 屏山县| 大悟县| 滦平县| 若尔盖县| 修武县| 潞城市| 彭山县| 辛集市| 凌云县| 牙克石市| 高州市| 大庆市| 镇安县| 任丘市| 江源县| 漳州市| 隆安县| 泸州市| 米林县| 拉萨市| 香格里拉县| 临猗县| 托克逊县|