与 Perl 和 Python 类似,Ruby 拥有出色的功能,是一种强大的文本处理语言。本文简单介绍了 Ruby 的文本数据处理功能,以及如何使用 Ruby 语言有效处理不同格式的文本数据,无论是 CSV 数据还是 XML 数据。
Ruby 字符串
常用缩略词
- CSV:逗号分隔值
- REXML:Ruby Electric XML
- XML:可扩展标记语言
Ruby 中的 String 是容纳、比较和操作文本数据的一种强大方法。在 Ruby 中,String 是一个类,可以通过调用 String::new 或向它分配一个字面值将它实例化。
向 Strings 赋值时,可以使用单引号(')或双引号(")来包围值。单引号和双引号在为 Strings 赋值时有几个差别。双引号支持转义序列使用一个前置反斜杠(\)并支持在字符串中使用 #{} 操作符计算表达式。而单引号引用的字符串则是简单直接的文字。
清单 1 是一个示例。
清单 1. 处理 Ruby 字符串:定义字符串
message = 'Heal the World…' puts message message1 = "Take home Rs #{100*3/2} " puts message1 Output : # ./string1.rb # Heal the World… # Take home Rs 150
这里,第一个字符串使用一对单引号定义,第二个字符串使用一对双引号定义。在第二个字符串中,#{} 中的表达式在显示前计算。
另一种有用的字符串定义方法通常用于多行字符串定义。
从现在开始,我将使用交互式 Ruby 控制台 irb 进行说明。您的 Ruby 安装也应该安装该控制台。如果没有安装,建议您获取 irb Ruby gem 并安装它。Ruby 控制台是学习 Ruby 及其模块的一个非常有用的工具。安装之后,可以使用 irb 命令运行它。
清单 2. 处理 Ruby 字符串:定义多个字符串
irb str = EOF irb "hello world irb "how do you feel"how r u "hello, world\nhow do you feel" irb puts str hello, world how do you feel"htmlcode">irb str = "The world for a horse" # String initialized with a value The world for a horse irb str*2 # Multiplying with an integer returns a # new string containing that many times # of the old string. The world for a horseThe world for a horse irb str + " Who said it " # Concatenation of strings using the '+' operator The world for a horse Who said it " is it" # Concatenation using the '<<' operator The world for a horse is it"htmlcode">irb str[0] # The '[]' operator can be used to extract substrings, just # like accessing entries in an array. # The index starts from 0. 84 # A single index returns the ascii value # of the character at that position irb str[0,5] # a range can be specified as a pair. The first is the starting # index , second is the length of the substring from the # starting index. The w irb str[16,5]="Ferrari" # The same '[]' operator can be used # to replace substrings in a string # by using the assignment like '[]=' irbstr The world for a Ferrari Irb str[10..22] # The range can also be specified using [x1..x2] for a Ferrari irb str[" Ferrari"]=" horse" # A substring can be specified to be replaced by a new # string. Ruby strings are intelligent enough to adjust the # size of the string to make up for the replacement string. irb s The world for a horse irb s.split # Split, splits the string based on the given delimiter # default is a whitespace, returning an array of strings. ["The", "world", "for", "a", "horse"] irb s.each(' ') { |str| p str.chomp(' ') } # each , is a way of block processing the # string splitting it on a record separator # Here, I use chomp() to cut off the trailing space "The" "world" "for" "a" "horse"Ruby String 类还可以使用许多其他实用方法,这些方法可以更改大小写、获取字符串长度、删除记录分隔符、扫描字符串、加密、解密等。另一个有用的方法是 freeze,该方法可以使字符串变得不可修改。对 String str 调用该方法(str.freeze)之后,str 将不能被修改。
Ruby 还有一些称为 “析构器(destructor)” 的方法。以感叹号(!)结尾的方法将永久修改字符串。常规方法(结尾没有感叹号)修改并返回调用它们的字符串的副本。而带有感叹号的方法直接修改调用它们的字符串。
清单 5. 处理 Ruby 字符串:永久修改字符串irb str = "hello, world" hello, world irb str.upcase HELLO, WORLD irbstr # str, remains as is. Hello, world irb str.upcase! # here, str gets modified by the '!' at the end of # upcase. HELLO, WORLD irb str HELLO, WORLD在 清单 5 中,str 中的字符串由 upcase! 方法修改,但 upcase 方法只返回大小写修改后的字符串副本。这些 ! 方法有时很有用。
Ruby Strings 的功能非常强大。数据被捕获进 Strings 中后,您就能够任意使用多种方法轻松有效地处理这些数据。
处理 CSV 文件
CSV 文件是表示表格式的数据的一种很常见的方法,表格式通常用作从电子表格导出的数据(比如带有详细信息的联系人列表)的格式。
Ruby 有一个强大的库,可以用于处理这些文件。csv 是负责处理 CSV 文件的 Ruby 模块,它拥有创建、读取和解析 CSV 文件的方法。
清单 6 展示了如何创建一个 CSV 文件并使用 Ruby csv 模块来解析文件。
清单 6. 处理 CSV 文件:创建并解析一个 CSV 文件require 'csv' writer = CSV.open('mycsvfile.csv','w') begin print "Enter Contact Name: " name = STDIN.gets.chomp print "Enter Contact No: " num = STDIN.gets.chomp s = name+" "+num row1 = s.split writer << row1 print "Do you want to add more " ans = STDIN.gets.chomp end while ans != "n" writer.close file = File.new('mycsvfile.csv') lines = file.readlines parsed = CSV.parse(lines.to_s) p parsed puts "" puts "Details of Contacts stored are as follows..." puts "" puts "-------------------------------" puts "Contact Name | Contact No" puts "-------------------------------" puts "" CSV.open('mycsvfile.csv','r') do |row| puts row[0] + " | " + row[1] puts "" end清单 7 显示了输出:
清单 7. 处理 CSV 文件:创建并解析一个 CSV 文件输出Enter Contact Name: Santhosh Enter Contact No: 989898 Do you want to add more "htmlcode"><cart id="userid"> <item code="item-id"> <price> <price/unit> </price> <qty> <number-of-units> </qty> </item> </cart>从 下载 部分获取这个示例 XML 文件。现在,加载这个 XML 文件并使用 REXML 解析文件树。
清单 9. 处理 XML 文件:解析 XML 文件require 'rexml/document' include REXML file = File.new('shoppingcart.xml') doc = Document.new(file) root = doc.root puts "" puts "Hello, #{root.attributes['id']}, Find below the bill generated for your purchase..." puts "" sumtotal = 0 puts "-----------------------------------------------------------------------" puts "Item\t\tQuantity\t\tPrice/unit\t\tTotal" puts "-----------------------------------------------------------------------" root.each_element('//item') { |item| code = item.attributes['code'] qty = item.elements["qty"].text.split(' ') price = item.elements["price"].text.split(' ') total = item.elements["price"].text.to_i * item.elements["qty"].text.to_i puts "#[code]\t\t #{qty}\t\t #{price}\t\t #{total}" puts "" sumtotal += total } puts "-----------------------------------------------------------------------" puts "\t\t\t\t\t\t Sum total : " + sumtotal.to_s puts "-----------------------------------------------------------------------"清单 10 显示输出。
清单 10. 处理 XML 文件:解析 XML 文件输出Hello, santhosh, Find below the bill generated for your purchase... ------------------------------------------------------------------------- Item Quantity Price/unit Total ------------------------------------------------------------------------- CS001 2 100 200 CS002 5 200 1000 CS003 3 500 1500 CS004 5 150 750 ------------------------------------------------------------------------- Sum total : 3450 --------------------------------------------------------------------------清单 9 解析这个购物车 XML 文件并生成一个账单,该账单显示项目合计和采购总计(见 清单 10)。
下面我们具体介绍操作过程。
首先,包含 Ruby 的 REXML 模块,该模块拥有解析 XML 文件的方法。
打开 shoppingcart.xml 文件并从该文件创建一个 Document 对象,该对象包含解析后的 XML 文件。
将文档的根分配给元素对象 root。这将指向 XML 文件中的 cart 标记。
每个元素对象拥有一个属性对象,该属性对象是元素属性的 hash 表,其中属性名称作为键名,属性值作为键值。这里,root.attributes['id'] 将提供 root 元素的 id 属性的值(本例中为 userid)。
下面,将 sumtotals 初始化为 0 并打印标头。
每个元素对象还有一个对象 elements,该对象拥有 each 和 [] 方法,以便访问子元素。这个对象遍历所有带有 item 名称(通过 XPath 表达式 //item 指定)的 root 元素的子元素。每个元素还有一个属性 text,该属性容纳元素的文本值。
下一步,获取 item 元素的 code 属性以及 price 和 qty 元素的文本值,然后计算项目合计(Total)。将详细信息打印到账单并将项目合计添加到采购总计(Sum total)。
最后,打印采购总计。
这个示例展示了使用 REXML 和 Ruby 解析 XML 文件有多么简单!同样,在运行中生成 XML 文件,添加和删除元素及它们的属性也很简单。
清单 11. 处理 XML 文件:生成 XML 文件doc = Document.new doc.add_element("cart1", {"id" => "user2"}) cart = doc.root.elements[1] item = Element.new("item") item.add_element("price") item.elements["price"].text = "100" item.add_element("qty") item.elements["qty"].text = "4" cart .elements << item清单 11 中的代码通过创建一个 cart 元素、一个 item 元素和它的子元素来创建 XML 结构,然后使用值填充这些子元素并将它们添加到 Document 根。
类似地,要删除元素和属性,使用 Elements 对象的 delete_element 和 delete_attribute 方法。
以上示例中的方法称为树解析(tree parsing)。另一种 XML 文档解析方法称为流解析(stream parsing)。“流解析” 比 “树解析” 更快,可以用于要求快速解析的情况。“流解析” 是基于事件的,它使用监听器。当解析流遇到一个标记时,它将调用监听器并执行处理。
清单 12 展示了一个示例:
清单 12. 处理 XML 文件:流解析require 'rexml/document' require 'rexml/streamlistener' include REXML class Listener include StreamListener def tag_start(name, attributes) puts "Start #{name}" end def tag_end(name) puts "End #{name}" end end listener = Listener.new parser = Parsers::StreamParser.new(File.new("shoppingcart.xml"), listener) parser.parse清单 13 显示输出:
清单 13. 处理 XML 文件:流解析输出Start cart Start item Start price End price Start qty End qty End item Start item Start price End price Start qty End qty End item Start item Start price End price Start qty End qty End item Start item Start price End price Start qty End qty End item End cart这样,REXML 和 Ruby 联合起来为您提供一种非常有效和直观地处理和操作 XML 数据的强大方法。
结束语
Ruby 拥有一组很好的内置库和外部库,支持快速、强大和有效的文本处理。您可以利用该功能简化和改进可能遇到的各种文本数据处理工作。本文只是 Ruby 的文本处理功能的简要介绍,您可以进一步深入了解该功能。
毋庸置疑,Ruby 是您需要的一个强大工具。