與 Perl 和 Python 類似,Ruby 擁有出色的功能,是一種強大的文本處理語言。本文簡單介紹了 Ruby 的文本數(shù)據(jù)處理功能,以及如何使用 Ruby 語言有效處理不同格式的文本數(shù)據(jù),無論是 CSV 數(shù)據(jù)還是 XML 數(shù)據(jù)。
Ruby 字符串
常用縮略詞
- CSV:逗號分隔值
- REXML:Ruby Electric XML
- XML:可擴展標記語言
Ruby 中的 String 是容納、比較和操作文本數(shù)據(jù)的一種強大方法。在 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
這里,第一個字符串使用一對單引號定義,第二個字符串使用一對雙引號定義。在第二個字符串中,#{} 中的表達式在顯示前計算。
另一種有用的字符串定義方法通常用于多行字符串定義。
從現(xiàn)在開始,我將使用交互式 Ruby 控制臺 irb>> 進行說明。您的 Ruby 安裝也應該安裝該控制臺。如果沒有安裝,建議您獲取 irb Ruby gem 并安裝它。Ruby 控制臺是學習 Ruby 及其模塊的一個非常有用的工具。安裝之后,可以使用 irb>> 命令運行它。
清單 2. 處理 Ruby 字符串:定義多個字符串
irb>> str = >>EOF
irb>> "hello world
irb>> "how do you feel?
irb>> "how r u ?
irb>> EOF
"hello, world\nhow do you feel?\nhow r u?\n"
irb>> puts str
hello, world
how do you feel?
how r u?
在 清單 2 中,>>EOF 和 EOF 中的所有內容都視為字符串的一部分,包括 \n(換行)字符。
Ruby String 類有一組強大的方法用于操作和處理存儲在它們之中的數(shù)據(jù)。清單 3、4 和 5 中的示例展示了部分方法。
清單 3. 處理 Ruby 字符串:連接字符串
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 ?
irb>> str" is it? " # Concatenation using the '' operator
The world for a horse is it?
提取子字符串并操作字符串的多個部分
清單 4. 處理 Ruby 字符串:提取并操作
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 '[]='
irb>>str
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)” 的方法。以感嘆號(!)結尾的方法將永久修改字符串。常規(guī)方法(結尾沒有感嘆號)修改并返回調用它們的字符串的副本。而帶有感嘆號的方法直接修改調用它們的字符串。
清單 5. 處理 Ruby 字符串:永久修改字符串
irb>> str = "hello, world"
hello, world
irb>> str.upcase
HELLO, WORLD
irb>>str # 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 的功能非常強大。數(shù)據(jù)被捕獲進 Strings 中后,您就能夠任意使用多種方法輕松有效地處理這些數(shù)據(jù)。
處理 CSV 文件
CSV 文件是表示表格式的數(shù)據(jù)的一種很常見的方法,表格式通常用作從電子表格導出的數(shù)據(jù)(比如帶有詳細信息的聯(lián)系人列表)的格式。
Ruby 有一個強大的庫,可以用于處理這些文件。csv 是負責處理 CSV 文件的 Ruby 模塊,它擁有創(chuàng)建、讀取和解析 CSV 文件的方法。
清單 6 展示了如何創(chuàng)建一個 CSV 文件并使用 Ruby csv 模塊來解析文件。
清單 6. 處理 CSV 文件:創(chuàng)建并解析一個 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 ? (y/n): "
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 文件:創(chuàng)建并解析一個 CSV 文件輸出
Enter Contact Name: Santhosh
Enter Contact No: 989898
Do you want to add more ? (y/n): y
Enter Contact Name: Sandy
Enter Contact No: 98988
Do you want to add more ? (y/n): n
Details of Contacts stored are as follows...
---------------------------------
Contact Name | Contact No
---------------------------------
Santhosh | 989898
Sandy | 98988
讓我們快速檢查一下這個示例。
首先,包含 csv 模塊(require 'csv')。
要創(chuàng)建一個新的 CSV 文件 mycsvfile.csv,使用 CSV.open() 調用打開它。這返回一個寫入器(writer)對象。
這個示例創(chuàng)建了一個 CSV 文件,該文件包含一個簡單的聯(lián)系人列表,存儲聯(lián)系人姓名及其電話號碼。在循環(huán)中,用戶被要求輸入聯(lián)系人姓名和電話號碼。姓名和電話號碼被連接為一個字符串,然后分割為含兩個字符串的數(shù)組。這個數(shù)組傳遞到寫入器對象以便寫入 CSV 文件。這樣,一對 CSV 值就存儲為文件中的一行。
循環(huán)結束后,任務也就完成了。現(xiàn)在關閉寫入器,文件中的數(shù)據(jù)得以保存。
下一步是解析創(chuàng)建的 CSV 文件。
打開和解析該文件的一種方法是使用新的 CSV 文件名稱創(chuàng)建一個新的 File 對象。
調用 readlines 方法將文件中的所有行讀入一個名為 lines 的數(shù)組。
通過調用 lines.to_s 將 lines 數(shù)組轉換為一個 String 對象,然后將這個 String 對象傳遞到 CSV.parse 方法,該方法解析 CSV 數(shù)據(jù)并將其內容返回為一個包含數(shù)組的數(shù)組。
下面介紹打開和解析該文件的另一種方法。以讀取模式使用 CSV.open 調用再次打開文件。這返回一個行數(shù)組。使用某種格式打印每個行以顯示聯(lián)系人細節(jié)。這里的每個行對應文件中的行。
如您所見,Ruby 提供一個強大的模塊來處理 CSV 文件和數(shù)據(jù)。
處理 XML 文件
對于 XML 文件,Ruby 提供一個名為 REXML 的強大的內置庫。這個庫可以用于讀取和解析 XML 文檔。
查看以下 XML 文件并試圖用 Ruby 和 REXML 來解析它。
下面是一個簡單的 XML 文件,列示一個在線購物中心的典型購物車中的內容。它擁有以下元素:
- cart —— 根元素
- user —— 購貨用戶
- item —— 用戶添加到購物車中的商品項
- id, price 和 quantity —— 項目的子元素
清單 8 展示了這個 XML 的結構:
清單 8. 處理 XML 文件:示例 XML 文件
cart id="userid">
item code="item-id">
price>
price/unit>
/price>
qty>
number-of-units>
/qty>
/item>
/cart>
從 下載 部分獲取這個示例 XML 文件?,F(xiàn)在,加載這個 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 文件并從該文件創(chuàng)建一個 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 中的代碼通過創(chuàng)建一個 cart 元素、一個 item 元素和它的子元素來創(chuàng)建 XML 結構,然后使用值填充這些子元素并將它們添加到 Document 根。
類似地,要刪除元素和屬性,使用 Elements 對象的 delete_element 和 delete_attribute 方法。
以上示例中的方法稱為樹解析(tree parsing)。另一種 XML 文檔解析方法稱為流解析(stream parsing)。“流解析” 比 “樹解析” 更快,可以用于要求快速解析的情況?!傲鹘馕觥?是基于事件的,它使用監(jiān)聽器。當解析流遇到一個標記時,它將調用監(jiān)聽器并執(zhí)行處理。
清單 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 聯(lián)合起來為您提供一種非常有效和直觀地處理和操作 XML 數(shù)據(jù)的強大方法。
結束語
Ruby 擁有一組很好的內置庫和外部庫,支持快速、強大和有效的文本處理。您可以利用該功能簡化和改進可能遇到的各種文本數(shù)據(jù)處理工作。本文只是 Ruby 的文本處理功能的簡要介紹,您可以進一步深入了解該功能。
毋庸置疑,Ruby 是您需要的一個強大工具。
您可能感興趣的文章:- 利用RJB在Ruby on Rails中使用Java代碼的教程
- 使用Ruby編寫腳本進行系統(tǒng)管理的教程
- Ruby中關于hash的基本使用方法