Ruby Study 3 : String and Range class

简介:
1. Normal String Delimiter ( ' and " )
前面两篇已经接触了很多String的例子, 下面再举一个, 注意看单引号和双引号的区别 :
s1 = 'Hello'
s2 = 'World'
s3 = '#{s1} #{s2}'
s4 = "#{s1} #{s2}"
puts(s3)
puts(s4)

执行结果 :
#{s1} #{s2}
Hello World

2. User Defined String Delimiter
当String中有单引号或双引号比较多时, 需要很多转义. 那么有没有更简洁的输入方法呢 :
s1 = 'I\'m Digoal'
s2 = "This is a double quota\""

puts(s1)
puts(s2

执行结果 : 
I'm Digoal
This is a double quota"

单引号 : 使用%q// , 非数字字母的符合替代/. (如%q{}, %q!!, 等)
双引号 :  使用%Q// , 非数字字母的符合替代/.  (如%Q{}, %Q!!, 等)
双引号 :  使用%// , 非数字字母的符合替代/.  (如%{}, %!!, 等)
s1 = 'I\'m Digoal'
s2 = "This is a double quota\""
s3 = %q/I'm Digoal/
s4 = %Q(This is a double quota")
s5 = %q{#{s3} #{s4}}
s6 = %Q{#{s3} #{s4}}
s7 = %*#{s3} #{s4}*
puts(s1)
puts(s2)
puts(s3)
puts(s4)
puts(s5)
puts(s6)
puts(s7)

执行结果 :
I'm Digoal
This is a double quota"
I'm Digoal
This is a double quota"
#{s3} #{s4}
I'm Digoal This is a double quota"
I'm Digoal This is a double quota"


3. Backquotes (execute OS command)
在Ruby中执行操作系统命令有点类似SHELL脚本, 用反引号.
#!/opt/ruby/bin/ruby
print("Please enter dir name, then i can list it:")
dir = gets().chomp
ls = `ls -la #{dir}`
puts(ls)

输入 / 后,  执行结果 :
total 204
drwxr-xr-x  29 root     root      4096 Feb  8 17:35 .
drwxr-xr-x  29 root     root      4096 Feb  8 17:35 ..
-rw-r--r--   1 root     root         0 Dec 27 14:30 .autofsck
-rw-r--r--   1 root     root         0 Oct 21 11:05 .autorelabel
drwxr-xr-x   2 root     root      4096 Feb  8 17:07 bin
drwxr-xr-x   3 root     root      4096 Oct 21 10:49 boot
drwxr-xr-x  14 root     root      4120 Dec 27 14:30 dev
drwxr-xr-x  97 root     root     12288 Feb 25 04:02 etc
drwxr-xr-x   5 postgres postgres  4096 Dec 26 14:58 hds1
drwxr-xr-x   4 postgres postgres  4096 Dec 26 14:58 hds2
drwxr-xr-x   7 root     root      4096 Feb  8 16:42 home
drwxr-xr-x  11 root     root      4096 Oct 21 12:29 lib
drwxr-xr-x   9 root     root     12288 Oct 21 12:28 lib64
drwx------   2 root     root     16384 Oct 21 18:44 lost+found
drwxr-xr-x   2 root     root      4096 May 11  2011 media
drwxr-xr-x   2 root     root         0 Dec 27 14:30 misc
drwxr-xr-x   2 root     root      4096 May 11  2011 mnt
drwxr-xr-x   2 root     root         0 Dec 27 14:30 net
drwxr-xr-x  11 root     root      4096 Feb 15 10:00 opt
drwxr-xr-x   3 postgres postgres  4096 Oct 21 11:08 pgdata
drwx------  14 pg92     pg92      4096 Feb 24 14:22 pgdata1919
drwxr-xr-x   3 pgxc     pgxc      4096 Feb  8 17:35 pgxc_gtm
dr-xr-xr-x 223 root     root         0 Dec 27 22:29 proc
drwxr-x---   9 root     root      4096 Feb 24 15:58 root
drwxr-xr-x   2 root     root     12288 Oct 21 12:29 sbin
drwxr-xr-x   2 root     root      4096 Oct 21 10:45 selinux
drwxr-xr-x   2 root     root      4096 May 11  2011 srv
drwxr-xr-x  11 root     root         0 Dec 27 22:29 sys
drwxrwxrwt   5 root     root      4096 Feb 28 09:01 tmp
drwxr-xr-x  15 root     root      4096 Oct 21 10:46 usr
drwxr-xr-x  24 root     root      4096 Oct 21 16:40 var

与前面的自定义String delimiter一样, 反引号可以用%x//来替代.
#!/opt/ruby/bin/ruby
print("Please enter dir name, then i can list it:")
dir = gets().chomp
ls = %x/ls -la #{dir}/  # 或者使用%x{}等.
puts(ls)

4. String Concatenation
String的连接操作, 有些是会改变操作符左边的字符的, 有些不会改. 我们来看个例子 : 
( <<, +, 空格 )
s1 = "Hello"
s2 = s1 << " World" # << 方法将改变s1的值.
puts(s1)
puts(s2)
s3 = "Digoal"
s4 = s3 + " Zhou" # + 方法不会改变s3的值.
puts(s3)
puts(s4)
s5 = "Digoal" " Zhou"  # 空格只能用于两个单引号和双引号包围的字符串的连接
#s7 = %Q{Digoal} %Q{ Zhou}  #不允许, 异常
#s8 = 'Digoal' s3   #不允许, 异常
#s9 = s3 ' Zhou'   #不允许, 异常
puts(s5)

执行结果 :
Hello World
Hello World
Digoal
Digoal Zhou
Digoal Zhou

另外还有一个需要注意的是, integer如果出现在这些连接方法的右边, 会显示什么 ? 
<< 中, 0-255会字段转换成ASCII码对应的字符.
+ 则必须使用to_s方法转换成String. 否则报错. 并且输出的是数字本身. 当然在<<中如果使用to_s也是显示数字本身.
s1 = "This " << "is" << " a string " << 36 # char 36 is '$'
s2 = "This "  + "is" + " a string "  + 36.to_s
s3 = "This "  "is"  " a string "  + 36.to_s
puts("(s1):" << s1)
puts("(s2):" << s2)
puts("(s3):" << s3)

执行结果 : 
(s1):This is a string $
(s2):This is a string 36
(s3):This is a string 36

5. Comma Used with String (return Array)
注意使用<<, + , 空格返回的都是什么类型呢 ?
s1 = "Hello " << "World"
s2 = "Digoal " + "Zhou"
s3 = "A" "DBA"
puts(s1.class)
puts(s2.class)
puts(s3.class)

执行结果 : 
String
String
String

那么接下来看看使用逗号连接会返回什么类型 :
s1 = "Hello " , "World"
puts(s1.class)

执行结果 : 
Array  # 返回的是Array类型, 可不是String哦.

6. String Assignment
从上一个例子我们知道<<会修改左边字符串, 而+不会修改它左边的字符串.
那么看看还有哪些方法会修改左边字符串的值, (一般以!结尾的方法是会修改左边字符串的值的)
s = "hello world"
print( "1) s='#{s}' and s.object_id=#{s.object_id}\n" )
s = s + "!"            # this creates a new string object
print( "2) s='#{s}' and s.object_id=#{s.object_id}\n" )
s = s.capitalize      # this creates a new string object
print( "3) s='#{s}' and s.object_id=#{s.object_id}\n" )
s.capitalize!      # but this modifies the original string object
print( "4) s='#{s}' and s.object_id=#{s.object_id}\n" )
s[1] = 'A'          # this also modifies the original string object
print( "5) s='#{s}' and s.object_id=#{s.object_id}\n" )
s << ' Digoal'          # this also modifies the original string object
print( "6) s='#{s}' and s.object_id=#{s.object_id}\n" )

执行结果 :
1) s='hello world' and s.object_id=15923760 # 给String的对象赋值(不管这个值是否与原来的值相等)会改变object_id
2) s='hello world!' and s.object_id=15923664 
3) s='Hello world!' and s.object_id=15923592 # 以下几个操作之后, object_id都没有变化, 但是s的值已经被修改了.
4) s='Hello world!' and s.object_id=15923592
5) s='HAllo world!' and s.object_id=15923592
6) s='HAllo world! Digoal' and s.object_id=15923592

给Fixnum和String的对象赋值。看看object_id会不会发送改变 : 
i1 = 10
s1 = "Digoal"
puts(i1.class)
puts(i1.object_id)
puts(s1.class)
puts(s1.object_id)
# 以变量的形式赋值给新的变量, 看看新变量的object_id, 等于前者的OBJECT_ID
i2 = i1
s2 = s1
puts(i2.object_id)
puts(s2.object_id)
# 使用相同的值赋值给新的变量, String新变量的object_id与前者不同. 但是Fixnum类的对象的object_id相同.
i3 = 10
s3 = "Digoal"
puts(i3.object_id)
puts(s3.object_id)
# 使用相同的值覆盖相同的变量, 看看object_id会不会变化, String类的对象的object_id会变化, Fixnum类的对象只要值一样, OBJECT_ID都一样.
i3 = 10
s3 = "Digoal"
puts(i3.object_id)
puts(s3.object_id)

执行结果 :
Fixnum
21
String
16221864
21
16221864
21
16221600
21
16221516

7. Indexing into a String
一个字符串, 其中的每个字符都有一个标记, 从0开始. 来看个例子 :
s = "Hello"
length = s.length
(0...length).each {  # 三个点的Range类不包含最大值.
  |x|
  puts(s[x])
}

执行结果 : 
H
e
l
l
o

注意1.8中用s[x]输出的是字符的ASCII值, 1.9输出的是字符本身. 如果要在1.9中输出ASCII怎么办呢, 用ord方法.
s = "Hello"
puts(s[0])
puts(s[0].ord)

执行结果 :
H
72

还有一个玩法 : 
s = "Hello , I'm Digoal"
puts(s[0,4])   # 从0开始, 输出4个字符.
puts(s[-6,6])   # 从倒数第6个开始, 输出6个字符.
puts(s[(1...4)]) # 从1到4, 不包括4.
puts(s[(1..4)])  # 从1到4, 包括4
puts(s[(-6..-1)])  # 从-6到-1. 包括-6和-1

执行结果 :
Hell
Digoal
ell
ello
Digoal

接下来列举一些String类的方法 : 
当然你可以使用String.methods打印出来看看到底有多少方法, 然后到API里面去学习它们的用法 :
s = "Hello , I'm Digoal"
puts(s.length)
puts(s.reverse!)
puts(s.reverse)
puts(s.upcase)
puts(s.capitalize)
puts(s.swapcase)
puts(s.downcase)
puts(s.insert(7,"NOT "))  # 注意这里的7是从0开始的哦,不是从1开始的. 是在index 7 之前插入的意思.
puts(s.squeeze)
puts(s.split)

输出结果 : 
18
laogiD m'I , olleH
Hello , I'm Digoal
LAOGID M'I , OLLEH
Laogid m'i , olleh
LAOGId M'i , OLLEh
laogid m'i , olleh
laogiD NOT m'I , olleH
laogiD NOT m'I , oleH
laogiD
NOT
m'I
,
olleH


8. chomp(safer) and chop
先介绍一个$/ , 默认是\n. ASCII码=10. 这个字符串可以修改, 用于gets()时, 表示$/以后的字符不接收. $/本身接收 .
用在chomp()方法, 在末尾时可以去除这个字符串.
puts($/.class)
puts($/.ord)

执行结果 :
String
10

chomp用于去除字符串末尾的\n, \r 或 \r\n.  或者$/, \n$/, \r$/, \r\n$/
$/ = "ok"
puts("let's go0ok".chomp())
puts("let's go1\r\nok".chomp())
puts("let's go2\nok".chomp())
puts("let's go3\rok".chomp())
puts("let's go4\r".chomp())
puts("let's go5\n".chomp())
puts("let's go6\r\n".chomp())
# 以下则不能全部去除
puts("let's go7\n\r".chomp())
puts("let's go8ok\n".chomp())
puts("let's go9ok\r\n".chomp())

执行结果 :
let's go0
let's go1
let's go2
let's go3
let's go4
let's go5
let's go6
let's go7

let's go8ok
let's go9ok

chop则是用于去除最后一个字符的, 不管是什么字符.
$/ = "ok"
puts("let's go0ok".chop())

执行结果 :
let's go0o

再举一个gets()的例子 :
#!/opt/ruby/bin/ruby
$/ = "ok"
s = gets()
puts(s)

输入 : 
jfjjsj
nioooo  few ok ffewww good ok回车, # 第一个ok就表示记录结束了.
执行结果 :
jfjjsj
nioooo  few ok

9. Format Strings ( printf )
printf()方法的格式化输出 :
%d – decimal number
%f – floating-point number
%o – octal number
%p – inspect object
%s – string
%x – hexadecimal number


printf( "%f\n", 10.12945 )
printf( "%0.2f\n", 10.12945 )
printf("d=%d f=%f o=%o x=%x s=%s\n", 10, 10, 10, 10, 10)
printf("0.04f=%0.04f : 0.02f=%0.02f\n", 10.12945, 10.12945)
class Myclass
  def initialize(a,b)
    @x = a
    @y = b
  end
  attr_accessor( :x, :y )
end

ob1 = Myclass.new('digoal','zhou')
printf("inspect ob1: %p.\n",ob1)

执行结果 : 
10.129450
10.13
d=10 f=10.000000 o=12 x=a s=10
0.04f=10.1295 : 0.02f=10.13
inspect ob1: #<Myclass:0x1fb0960 @x="digoal", @y="zhou">.


10. Range
Range在Ruby中非常有意思, 在PostgreSQL 中用generate_series函数可以产生一连串的数字, 时间等.
在Ruby中用Range可以产生一串数字, 字符串, 浮点数等.
r1 = (1..10)  # 两个点表示包含最大和最小值
puts( r1.class )
puts( r1 )
puts( r1.count )
r2 = (1...10)  # 三个点表示不包含最大值
puts( r2.class )
puts( r2 )
puts( r2.count )

执行结果 :
Range
1..10
10
Range
1...10
9

把Range对象转换成Array对象 : (注意浮点型的Range对象不可以转换成Array对象, 会报错, 因为可能包含无穷数)
r1 = (1..10)
r2 = ('abc'..'def')
a1 = r1.to_a  # to_a方法用于将Range对象转换成Array对象.
a2 = r2.to_a
puts(a1.class)
puts(a2.class)
puts(a1)

执行结果 :
Array
Array
1
2
3
4
5
6
7
8
9
10


11. Iterating with a Range
其实Range和Array, Hash类型都有Iterate操作的. 来看个例子 :
r1 = ('a'..'z')
r1.each {  # 一个块,块非对象
  |x|  # 这是一个BLOCK内的变量.
  print(x)
}

执行结果 : 
abcdefghijklmnopqrstuvwxyz

12. Multi-line Strings ( <<EODOC )
多行字符串, 其实有点类似SHELL的玩法 :
s1 = <<EODOC  # 也可以写成<<'EODOC' , 则表示内部的字符串是用单引号包围的. 
The first line.
The second line.
The third line.
... and so on
EODOC  # EODOC必须在行首, 如果要不放行首, 可以在前面定义<<EODOC时改用<<-EODOC. 或者<<-'EODOC'

puts(s1)

执行结果 : 
The first line.
The second line.
The third line.
... and so on

当然也可以不叫EODOC, 例如<<EOF也行, 结束时使用EOF.

13. String Literals
这个玩法也和有意思, 和前面我们已经用到的%x//, %q//, %Q// 相似, 还有一些其他的玩法. 列举如下 :
%q/    /    # single-quoted
%Q/    /    # double-quoted
%/     /    # double-quoted
%w/    /    # array
%W/    /    # array double-quoted
%r|    |    # regular expression
%s/    /    # symbol
%x/    /    # operating system command

p %q/dog cat #{1+2}/        #=> "dog cat \#{1+2}"
p %Q/dog cat #{1+2}/        #=> "dog cat 3"
p %/dog cat #{1+2}/        #=> "dog cat 3"
p %w/dog cat #{1+2}/        #=> ["dog", "cat", "\#{1+2}"]
p %W/dog cat #{1+2}/        #=> ["dog", "cat", "3"]
p %r|^[a-z]*$|            #=> /^[a-z]*$/
p %s/dog/                #=> :dog
p %x/vol/                #=> " Volume in drive C is OS [etc...]"


【参考】
The Book Of Ruby
Ruby 1.9.3 API
相关文章
|
10月前
|
SQL 分布式计算 Spark
java.lang.StringIndexOutOfBoundsException: String index out of range: -2147483648 成功解决
java.lang.StringIndexOutOfBoundsException: String index out of range: -2147483648 成功解决
162 0