EasyTime - Ruby学习笔记
自我介绍
切换风格
订阅我的Blog
博客日历
文章归档...
最新发表...
博客统计...
网站链接...
资源
===========================================================
第二章 简单数据(三)
===========================================================

19Obscuring Strings

有时候我们不想字符串可被轻易阅读。例如,口令不应被以纯文本格式保存,不管如何设置文件的许可。

标准方法crypt使用DES加密字符串。它接受一个"salt"值做为参数(类似于随机数生成器的seed种子值)


下面显示了对它的一个很小应用,我们在这儿要求口令。

coded = "hfCghHIE5LAM."

puts "Speak, friend, and enter!"

print "Password: "

password = gets.chop

if password.crypt("hf") == coded

puts "Welcome!"

else

puts "What are you, an orc?"

end

还有另一种用于隐藏字符串方法。例如,我们有时候想隐藏文件中的字符串,以便它们不会被轻易阅读。甚至二进制文件都可用Unix字符串实用工具或其它来轻易地阅读一部分。而DES加密则更牢固一些。

值得注意的是,你不要在Web应用程序的服务器端来进行加密。这是因为进入Web的口令以明文形式在互联网上传输。像这种情况,最容易的安全措施是使用SSL。当然,你还可以使用对服务器端的加密,但是理由不同,是为了保护口令的存储而不是在传输期间。

20、统计字符串内的字符数

The count方法将统计任何指定字符的出现次数。

s1 = "abracadabra"

a = s1.count("c") # 1

b = s1.count("bdr") # 5

字符串参数类似于非常简单的正则表达式。如果以脱字符号^开始,列表内的将被否定。

c = s1.count("^a") # 6

d = s1.count("^bdr") # 6

连字号-指出字符的范围。

e = s1.count("a-d") # 9

f = s1.count("^a-d") # 2

21、反转字符串

字符串可以被reverse方法(相应有reverse!)轻易地反转。

s1 = "Star Trek"

s2 = s1.reverse # "kerT ratS"

s1.reverse! # s1 is now "kerT ratS"

假设你有个句子需要反转单词的次序(而不是字符的次序)。使用%w操作符生成单词数组,反转这个数组,然后使用join方法将它们重新连在一起。

words = %w( how now brown cow )

# ["how", "now", "brown", "cow"]

words.reverse.join(" ")

# "cow brown now how"

可以使用更一般化的String#split,它允许按你自己的模式分离单词。

phrase = "Now here's a sentence"

phrase.split(" ").reverse.join(" ")

# "sentence a here's Now"

22、移除重复字符

使用squeeze方法可以移除重复的字符。

s1 = "bookkeeper"

s2 = s1.squeeze # "bokeper"

s3 = "Hello..."

s4 = s3.squeeze # "Helo."

如果指定参数,则只有这些字符被压缩。

s5 = s3.squeeze(".") # "Hello."

这个参数遵循与count方法一样的规则;也就是说,它理解脱字符号和连字符。

也有squeeze!方法。

23、从字符串内移除指定字符

如果做为参数传递过来的字符出现在列表中,则delete方法将删除字符。

s1 = "To be, or not to be"

s2 = s1.delete("b") # "To e, or not to e"

s3 = "Veni, vidi, vici!"

s4 = s3.delete(",!") # "Veni vidi vici"

这个参数遵循与count方法一样的规则;也就是说,它理解脱字符号和连字符。

也有delete!方法。

24.打印特殊字符

dump方法将明确提供可打印的字符,它们通常有可见与不可见之分。

s1 = "Listen" << 7 << 7 << 7 # Add three ASCII BEL characters

puts s1.dump # Prints: Listen070707

s2 = "abcttdeftghinn"

puts s2.dump # Prints: abcttdeftghinn

s3 = "Double quote: ""

puts s3.dump # Prints: Double quote: "

25、生成连续字符串

我们很少想查找一个字符串连续值;例如,"aaa"的连续值是"aab"(然后是"aac", "aad",等等)

Ruby提供了succ方法来达到这个目的。

droid = "R2D2"

improved = droid.succ # "R2D3"

pill = "Vitamin B"

pill2 = pill.succ # "Vitamin C"

我们不推荐使用这个特性,除非值是可预见的和合理的。如果你的字符串足够长,你会得出令人不可思议的结果。

还有个upto方法,它将在循环中重复地应用succ方法,直到获得期望的值。

"Files, A".upto "Files, X" do |letter|

puts "Opening: #{ letter} "

end

# Produces 24 lines of output

相反,我们不主张频繁地使用它,使用它你会冒风险。同样,我们也想指出,在写本书时,还没有能替代它的相应的处理函数。

26Calculate the Levenstein Distance Between Two Strings

两个字符串之间距离的概念在智能语言(AI),密码系统,蛋白质搜索等其它领域都很重要。

The Levenstein distance (see Listing 2.3) is the minimum number of modifications needed to change one string into another, using three basic modification operations: del (deletion), ins (insertion), and sub (substitution). A substitution is also considered to be a combination of a deletion and insertion (indel). There are various approaches to this, but we will avoid getting too technical. Suffice it to say that this Ruby implementation allows you to provide optional parameters to set the cost for the three types of modification operations, and defaults to a single indel cost basis (cost of insertion=cost of deletion).

Listing 2.3 Levenstein Distance

class String

def levenstein(other, ins=2, del=2, sub=1)

# ins, del, sub are weighted costs

return nil if self.nil?

return nil if other.nil?

dm = [] # distance matrix

# Initialize first row values

dm[0] = (0..self.length).collect { |i| i * ins }

fill = [0] * (self.length - 1)

# Initialize first column values

for i in 1..other.length

dm[i] = [i * del, fill.flatten]

end

# populate matrix

for i in 1..other.length

for j in 1..self.length

# critical comparison

dm[i][j] = [

dm[i-1][j-1] +

(self[j-1] == other[i-1] ? 0 : sub),

dm[i][j-1] + ins,

dm[i-1][j] + del

].min

end

end

# The last value in matrix is the

# Levenstein distance between the strings

dm[other.length][self.length]

end

end

s1 = "ACUGAUGUGA"

s2 = "AUGGAA"

d1 = s1.levenstein(s2) # 9

s3 = "pennsylvania"

s4 = "pencilvaneya"

d2 = s3.levenstein(s4) # 7

s5 = "abcd"

s6 = "abcd"

d3 = s5.levenstein(s6) # 0

现在,我们已经定义了Levenstein距离,可以想像得到我们的类似定义?方法,以同样方式给出的。

class String

def similar?(other, thresh=2)

if self.levenstein(other) < thresh

true

else

false

end

end

end

if "polarity".similar?("hilarity")

puts "Electricity is funny!"

end

Of course, it would also be possible to pass in the three weighted costs to the similar? method so that they could in turn be passed into the Levenstein method. We have omitted these for simplicity.

27、使用字符串做堆栈和队列

可以将字符串视为堆栈或队列(Listing2.4),添加操作shift,unshift,push,pop,rotate_left,rotate_right。这些操作符有字符和单词两个级别。我们写一或二个程序来检验它们功能。当然,你也可以自己来做。

每个方法的返回值可能有些混乱。在重新取回操作符如popshift情况下,返回值是被重新取回的条目。在存储操作如pushunshift情况下,返回值是个新字符串。在所有旋转操作符情况下,返回值也是新字符串。我们在清晰地说一下:这些操作符的每一个都修改它接收者,尽管它们们没有使用感叹号!做为后缀标记出来。

Listing 2.4 String as Queues

class String

def shift

# self移除第一个字符并返回它,修改self

return nil if self.empty?

item=self[0]

self.sub!(/^./,"")

return nil if item.nil?

item.chr

end

def unshift(other)

# other字符串的最后一个字符添加到self的前面。

newself = other.to_s.dup.pop.to_s + self

self.replace(newself)

end

def pop

# 弹出self的最后一个字符并返回它,修改self

return nil if self.empty?

item=self[-1]

self.chop!

return nil if item.nil?

item.chr

end

def push(other)

#other的第一个字符放到self的尾部。

newself = self + other.to_s.dup.shift.to_s

self.replace(newself)

end

def rotate_left(n=1)

n=1 unless n.kind_of? Integer

n.times do

char = self.shift

self.push(char)

end

self

end

def rotate_right(n=1)

n=1 unless n.kind_of? Integer

n.times do

char = self.pop

self.unshift(char)

end

self

end

@@first_word_re = /^(w+W*)/

@@last_word_re = /(w+W*)$/

def shift_word

# Shifts first word off of self

# and returns; changes self

return nil if self.empty?

self=~@@first_word_re

newself= $' || "" # $' is POSTMATCH

self.replace(newself) unless $'.nil?

$1

end

def unshift_word(other)

# Adds provided string to front of self

newself = other.to_s + self

self.replace(newself)

end

def pop_word

# Pops and returns last word off

# self; changes self

return nil if self.empty?

self=~@@last_word_re

newself= $` || "" # $` is PREMATCH

self.replace(newself) unless $`.nil?

$1

end

def push_word(other)

# Pushes provided string onto end of self

newself = self + other.to_s

self.replace(newself)

end

def rotate_word_left

word = self.shift_word

self.push_word(word)

end

def rotate_word_right

word = self.pop_word

self.unshift_word(word)

end

alias rotate_Left rotate_word_left

alias rotate_Right rotate_word_right

end

# ------------

str = "Hello there"

puts str.rotate_left # "ello thereH"

puts str.pop # "H"

puts str.shift # "e"

puts str.rotate_right # "ello ther"

puts str.unshift("H") # "Hello ther"

puts str.push("e") # "Hello there"

puts str.push_word(", pal!") # "Hello there, pal!"

puts str.rotate_Left # "there, pal!Hello "

puts str.pop_word # str is "there, pal!"

# result is "Hello "

puts str.shift_word # str is "pal!"

# result is "there, "

puts str.unshift_word("Hi there, ") # "Hi there, pal!"

puts str.rotate_Right # "pal!Hi there, "

puts str.rotate_left(4) # "Hi there, pal!"

puts "Trying again..."

str = "pal! Hi there, "

puts str.rotate_left(5) # "Hi there, pal!"

注意带有范围的[ ]操作符被用于Note that the [] operator with a range might be used to gain a window onto a string that is being rotated.

str = ".....duck....*...*..*..........*......*..."

loop do

print str.rotate_left[0..7],"r"}

end

# speed reading

string="See Bill run. Run Bill run! See Jane sit. Jane sees Bill."

loop{ print string.rotate_Left[0..4],"r"}

my4java 发表于:2006.03.08 00:12 ::分类: ( Ruby Way 翻译 ) ::阅读:(718次) :: 评论 (0) :: 引用 (0)

发表评论
标题

在此添加评论

称呼

邮箱地址(可选)

个人主页(可选)

authimage