使用Ruby来处理文本的教程
与Perl和Python类似,Ruby拥有出色的功能,是一种强大的文本处理语言。本文简单介绍了Ruby的文本数据处理功能,以及如何使用Ruby语言有效处理不同格式的文本数据,无论是CSV数据还是XML数据。
Ruby字符串
常用缩略词
- CSV:逗号分隔值
- REXML:RubyElectricXML
- XML:可扩展标记语言
Ruby中的String是容纳、比较和操作文本数据的一种强大方法。在Ruby中,String是一个类,可以通过调用String::new或向它分配一个字面值将它实例化。
向Strings赋值时,可以使用单引号(')或双引号(")来包围值。单引号和双引号在为Strings赋值时有几个差别。双引号支持转义序列使用一个前置反斜杠(\)并支持在字符串中使用#{}操作符计算表达式。而单引号引用的字符串则是简单直接的文字。
清单1是一个示例。
清单1.处理Ruby字符串:定义字符串
message='HealtheWorld…' putsmessage message1="TakehomeRs#{100*3/2}" putsmessage1 Output: #./string1.rb #HealtheWorld… #TakehomeRs150
这里,第一个字符串使用一对单引号定义,第二个字符串使用一对双引号定义。在第二个字符串中,#{}中的表达式在显示前计算。
另一种有用的字符串定义方法通常用于多行字符串定义。
从现在开始,我将使用交互式Ruby控制台irb>>进行说明。您的Ruby安装也应该安装该控制台。如果没有安装,建议您获取irbRubygem并安装它。Ruby控制台是学习Ruby及其模块的一个非常有用的工具。安装之后,可以使用irb>>命令运行它。
清单2.处理Ruby字符串:定义多个字符串
irb>>str=>>EOF irb>>"helloworld irb>>"howdoyoufeel? irb>>"howru? irb>>EOF "hello,world\nhowdoyoufeel?\nhowru?\n" irb>>putsstr hello,world howdoyoufeel? howru?
在清单2中,>>EOF和EOF中的所有内容都视为字符串的一部分,包括\n(换行)字符。
RubyString类有一组强大的方法用于操作和处理存储在它们之中的数据。清单3、4和5中的示例展示了部分方法。
清单3.处理Ruby字符串:连接字符串
irb>>str="Theworldforahorse"#Stringinitializedwithavalue Theworldforahorse irb>>str*2#Multiplyingwithanintegerreturnsa #newstringcontainingthatmanytimes #oftheoldstring. TheworldforahorseTheworldforahorse irb>>str+"Whosaidit?"#Concatenationofstringsusingthe'+'operator TheworldforahorseWhosaidit? irb>>str<<"isit?"#Concatenationusingthe'<<'operator Theworldforahorseisit?
提取子字符串并操作字符串的多个部分
清单4.处理Ruby字符串:提取并操作
irb>>str[0]#The'[]'operatorcanbeusedtoextractsubstrings,just #likeaccessingentriesinanarray. #Theindexstartsfrom0. 84#Asingleindexreturnstheasciivalue #ofthecharacteratthatposition irb>>str[0,5]#arangecanbespecifiedasapair.Thefirstisthestarting #index,secondisthelengthofthesubstringfromthe #startingindex. Thew irb>>str[16,5]="Ferrari"#Thesame'[]'operatorcanbeused #toreplacesubstringsinastring #byusingtheassignmentlike'[]=' irb>>str TheworldforaFerrari Irb>>str[10..22]#Therangecanalsobespecifiedusing[x1..x2] foraFerrari irb>>str["Ferrari"]="horse"#Asubstringcanbespecifiedtobereplacedbyanew #string.Rubystringsareintelligentenoughtoadjustthe #sizeofthestringtomakeupforthereplacementstring. irb>>s Theworldforahorse irb>>s.split#Split,splitsthestringbasedonthegivendelimiter #defaultisawhitespace,returninganarrayofstrings. ["The","world","for","a","horse"] irb>>s.each(''){|str|pstr.chomp('')} #each,isawayofblockprocessingthe #stringsplittingitonarecordseparator #Here,Iusechomp()tocutoffthetrailingspace "The" "world" "for" "a" "horse"
RubyString类还可以使用许多其他实用方法,这些方法可以更改大小写、获取字符串长度、删除记录分隔符、扫描字符串、加密、解密等。另一个有用的方法是freeze,该方法可以使字符串变得不可修改。对Stringstr调用该方法(str.freeze)之后,str将不能被修改。
Ruby还有一些称为“析构器(destructor)”的方法。以感叹号(!)结尾的方法将永久修改字符串。常规方法(结尾没有感叹号)修改并返回调用它们的字符串的副本。而带有感叹号的方法直接修改调用它们的字符串。
清单5.处理Ruby字符串:永久修改字符串
irb>>str="hello,world" hello,world irb>>str.upcase HELLO,WORLD irb>>str#str,remainsasis. Hello,world irb>>str.upcase!#here,strgetsmodifiedbythe'!'attheendof #upcase. HELLO,WORLD irb>>str HELLO,WORLD
在清单5中,str中的字符串由upcase!方法修改,但upcase方法只返回大小写修改后的字符串副本。这些!方法有时很有用。
RubyStrings的功能非常强大。数据被捕获进Strings中后,您就能够任意使用多种方法轻松有效地处理这些数据。
处理CSV文件
CSV文件是表示表格式的数据的一种很常见的方法,表格式通常用作从电子表格导出的数据(比如带有详细信息的联系人列表)的格式。
Ruby有一个强大的库,可以用于处理这些文件。csv是负责处理CSV文件的Ruby模块,它拥有创建、读取和解析CSV文件的方法。
清单6展示了如何创建一个CSV文件并使用Rubycsv模块来解析文件。
清单6.处理CSV文件:创建并解析一个CSV文件
require'csv' writer=CSV.open('mycsvfile.csv','w') begin print"EnterContactName:" name=STDIN.gets.chomp print"EnterContactNo:" num=STDIN.gets.chomp s=name+""+num row1=s.split writer<<row1 print"Doyouwanttoaddmore?(y/n):" ans=STDIN.gets.chomp endwhileans!="n" writer.close file=File.new('mycsvfile.csv') lines=file.readlines parsed=CSV.parse(lines.to_s) pparsed puts"" puts"DetailsofContactsstoredareasfollows..." puts"" puts"-------------------------------" puts"ContactName|ContactNo" puts"-------------------------------" puts"" CSV.open('mycsvfile.csv','r')do|row| putsrow[0]+"|"+row[1] puts"" end
清单7显示了输出:
清单7.处理CSV文件:创建并解析一个CSV文件输出
EnterContactName:Santhosh EnterContactNo:989898 Doyouwanttoaddmore?(y/n):y EnterContactName:Sandy EnterContactNo:98988 Doyouwanttoaddmore?(y/n):n DetailsofContactsstoredareasfollows... --------------------------------- ContactName|ContactNo --------------------------------- Santhosh|989898 Sandy|98988
让我们快速检查一下这个示例。
首先,包含csv模块(require'csv')。
要创建一个新的CSV文件mycsvfile.csv,使用CSV.open()调用打开它。这返回一个写入器(writer)对象。
这个示例创建了一个CSV文件,该文件包含一个简单的联系人列表,存储联系人姓名及其电话号码。在循环中,用户被要求输入联系人姓名和电话号码。姓名和电话号码被连接为一个字符串,然后分割为含两个字符串的数组。这个数组传递到写入器对象以便写入CSV文件。这样,一对CSV值就存储为文件中的一行。
循环结束后,任务也就完成了。现在关闭写入器,文件中的数据得以保存。
下一步是解析创建的CSV文件。
打开和解析该文件的一种方法是使用新的CSV文件名称创建一个新的File对象。
调用readlines方法将文件中的所有行读入一个名为lines的数组。
通过调用lines.to_s将lines数组转换为一个String对象,然后将这个String对象传递到CSV.parse方法,该方法解析CSV数据并将其内容返回为一个包含数组的数组。
下面介绍打开和解析该文件的另一种方法。以读取模式使用CSV.open调用再次打开文件。这返回一个行数组。使用某种格式打印每个行以显示联系人细节。这里的每个行对应文件中的行。
如您所见,Ruby提供一个强大的模块来处理CSV文件和数据。
处理XML文件
对于XML文件,Ruby提供一个名为REXML的强大的内置库。这个库可以用于读取和解析XML文档。
查看以下XML文件并试图用Ruby和REXML来解析它。
下面是一个简单的XML文件,列示一个在线购物中心的典型购物车中的内容。它拥有以下元素:
- cart——根元素
- user——购货用户
- item——用户添加到购物车中的商品项
- id,price和quantity——项目的子元素
清单8展示了这个XML的结构:
清单8.处理XML文件:示例XML文件
<cartid="userid"> <itemcode="item-id"> <price> <price/unit> </price> <qty> <number-of-units> </qty> </item> </cart>
从下载部分获取这个示例XML文件。现在,加载这个XML文件并使用REXML解析文件树。
清单9.处理XML文件:解析XML文件
require'rexml/document' includeREXML file=File.new('shoppingcart.xml') doc=Document.new(file) root=doc.root puts"" puts"Hello,#{root.attributes['id']},Findbelowthebillgeneratedforyourpurchase..." 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\tSumtotal:"+sumtotal.to_s puts"-----------------------------------------------------------------------"
清单10显示输出。
清单10.处理XML文件:解析XML文件输出
Hello,santhosh,Findbelowthebillgeneratedforyourpurchase... ------------------------------------------------------------------------- ItemQuantityPrice/unitTotal ------------------------------------------------------------------------- CS0012100200 CS00252001000 CS00335001500 CS0045150750 ------------------------------------------------------------------------- Sumtotal: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)。将详细信息打印到账单并将项目合计添加到采购总计(Sumtotal)。
最后,打印采购总计。
这个示例展示了使用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方法。
以上示例中的方法称为树解析(treeparsing)。另一种XML文档解析方法称为流解析(streamparsing)。“流解析”比“树解析”更快,可以用于要求快速解析的情况。“流解析”是基于事件的,它使用监听器。当解析流遇到一个标记时,它将调用监听器并执行处理。
清单12展示了一个示例:
清单12.处理XML文件:流解析
require'rexml/document' require'rexml/streamlistener' includeREXML classListener includeStreamListener deftag_start(name,attributes) puts"Start#{name}" end deftag_end(name) puts"End#{name}" end end listener=Listener.new parser=Parsers::StreamParser.new(File.new("shoppingcart.xml"),listener) parser.parse
清单13显示输出:
清单13.处理XML文件:流解析输出
Startcart Startitem Startprice Endprice Startqty Endqty Enditem Startitem Startprice Endprice Startqty Endqty Enditem Startitem Startprice Endprice Startqty Endqty Enditem Startitem Startprice Endprice Startqty Endqty Enditem Endcart
这样,REXML和Ruby联合起来为您提供一种非常有效和直观地处理和操作XML数据的强大方法。
结束语
Ruby拥有一组很好的内置库和外部库,支持快速、强大和有效的文本处理。您可以利用该功能简化和改进可能遇到的各种文本数据处理工作。本文只是Ruby的文本处理功能的简要介绍,您可以进一步深入了解该功能。
毋庸置疑,Ruby是您需要的一个强大工具。