<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # **第 23 章 檢索郵政編碼** 正式進行數據檢索時一般都需要用到一些專門的框架或者應用程序,但如果只是對手頭的數據加以整理以方便處理的話,根據實際情況做個簡易的小工具也未嘗不可。在本章中,作為 Ruby 的應用示例,我們來看看如何檢索郵政編碼。 ### **23.1 獲取郵政編碼** 日本的郵政編碼可在郵局的官方網站上下載。 - **郵政編碼檢索**:[http://www.post.japanpost.jp/zipcode](http://www.post.japanpost.jp/zipcode) - **郵政編碼下載**:[http://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html](http://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html) - **郵政編碼說明**:[http://www.post.japanpost.jp/zipcode/dl/readme.html](http://www.post.japanpost.jp/zipcode/dl/readme.html) 下載后的文件格式是 zip,用 zip 工具解壓后就可以得到格式為 CSV、編碼為 Shift_JIS 的全日本的郵政編碼文件 `KEN_ALL.CSV`。 > **備注** 所謂 CSV 格式是指,`"aaa"`,`”bb”`,`”ccccc”` 這樣的值之間用逗號(`,`)做間隔的數據格式。 關于 CSV 中各個字段的含義,可在郵政編碼的說明頁面查詢。前 9 個字段的含義如下所示。 ① **日本地方公共團體編碼(JIS X0401、X0402):半角數字** ② **(舊)郵政編碼(5 位):半角數字** ③ **郵政編碼(7 位):半角數字** ④ **都道府縣名:半角片假名(按編碼順序排序)** ⑤ **市區町村名:半角片假名(按編碼順序排序)** ⑥ **町域名:半角片假名(按五十音順序排序)** ⑦ **都道府縣名:漢字(按編碼順序排序)** ⑧ **市區町村名:漢字(按編碼順序排序)** ⑨ **町域名:漢字(按五十音順序排序)** 另外,第 13 個字段表示的是“1 個郵政編碼表示多個町域”的情況,當這個值為 1 時,表示同一個郵政編碼會出現在多條數據中。 下面是實際文件中的 1 條數據,可以看出,各項目之間用逗號(`,`)做間隔,除了開頭和末尾的項目外,其他都用””括了起來。 ~~~ 01101,”060 “,”0600042”,”???????","????????????","????????(1-19 ????)","北海道","札幌市中央區","大通西(1?19丁目)",1,0,1,0,0,0 ~~~ ### **23.2 檢索郵政編碼** 首先我們先寫一個簡單的檢索程序,顯示郵政編碼所對應的數據(代碼清單 23.1)。為了獲知處理耗時,我們會獲取程序的開始和結束時間,并輸出兩者的差。在筆者的計算機上,整個處理過程大概用了 2 秒。 **代碼清單 23.1 split_zip.rb** ~~~ code = ARGV[0] start_time = Time.now # 獲取處理開始的時間 File.open("KEN_ALL.CSV","r:shift_jis").each_line do |line| line.chomp! rows = line.split(/,/) zipcode = rows[2].gsub(/"/,'') if zipcode == code puts line.encode('utf-8') end end p Time.now - start_time # 輸出處理結束時間與開始時間的差 ~~~ 通過代碼 23.1 可以看出,按照從文件開頭逐行讀取、檢索一致的郵政編碼這種形式,遍歷所有的行需要花幾秒時間。這種做法很實用,接下來我們再來看看有沒有更快的處理辦法。 ### **23.3 sqlite3 庫** 為了加快數據處理的速度,我們可以使用數據庫。這次我們使用開源的關系型數據庫 SQLite 以及操作數據庫用的語言 SQL,來對數據進行檢索、更新等操作。由于 SQLite 的第 3 版是最新版本,因此有時我們會直接稱之為 SQLite3。 - **SQLite 官方網站**:[http://www.sqlite.org/](http://www.sqlite.org/) 用 Ruby 操作 SQLite3,需要使用 `SQLite3` 庫。這里我們利用 gem 進行安裝。關于 gem 的內容,請參考 B.1 節。 > **執行示例** ~~~ > gem install sqlite3 ~~~ > **注** sqlite3 的 gem,在 Windows 中是經過編譯并已發布的二進制包,而在 Linux、Mac OS X 中,除了安裝對應發行版的包以外,還需要執行 gem 命令。有關安裝 sqlite3 的 gem 方面內容,我們已經在本書的官方網站([http://www.notwork.org/tanoshiiruby4/](http://www.notwork.org/tanoshiiruby4/))中做了補充,讀者可以參考。 數據庫中的數據是以“表”為單位管理的。1 張數據庫表就像 1 個 CSV 文件,表中有多行數據,每行數據中有多個項目。CSV 文件的格式恰好與數據庫表存放數據時的結構是一致的。在數據庫中創建這樣的數據庫表,我們就可以將數據保存到表中,使用 SQL 對數據進行插入、更新、刪除等操作。 讓我們先看看用 SQLite3 處理數據的例子。在保存數據前,首先需要準備保存數據用的表。這里,我們對名為 mydb.db 的數據庫文件創建 `ADDRBOOK` 表,用于保存名字與住址。以下是創建表的程序。 ~~~ SQLite3::Database.open “mydb.db” do |db| db.execute “CREATE TABLE ADDRBOOK (name TEXT, address TEXT)” end ~~~ 本書只用了 SQLite3 中的個別功能,實際只使用了兩個方法:一個是 SQLite3::Database 類的類方法 open 方法,另外一個也是 SQLite3::Database 類的實例方法 `execute` 方法。 `SQLite3::Database.open` 方法的第 1 個參數為數據庫的文件名。第 2 行的 `Database#execute` 方法,用于執行在 mydb.db 中創建新表 `ADDRBOOK` 的 `CREATE TABLE` 語句。接著在表中定義 了 `name`、`email`、`address` 和 tel 四個字段。1 為了可以保存任何長度的字符串,各字段的類型都定義為沒有長度限制的 TEXT 類型。創建表后,像下面那樣對表插入數據。 1在上面的例子中實際只定義了 name、address 兩個字段。——譯者注 ~~~ SQLite3::Database.open “mydb.db” do |db| db.execute “INSERT INTO ADDRBOOK VALUES (?, ?), [col1, col2]” end ~~~ 第 1 行的 `SQLite3::Database.open` 方法和之前的一樣。第 2 行的 `Database#execute` 方法執行的是 `INSERT` 語句,這是向數據庫插入數據的 SQL。(?, ?) 表示表中的字段,分別用 `col1` 及 `col2` 對這兩個字段進行賦值。 最后,用以下方法讀取數據。 ~~~ SQLite3::Database.open “mydb.db” do |db| db.execute(“SELECT * FROM ADDRBOOK”) do |rows| p rows end end ~~~ 同樣是執行 `execute` 方法,不過參數的字符串要變為 SQL 的 `SELECT` 語句。另外,`execute` 方法可以使用塊,塊變量就是數組形式的 SQL 的執行結果。 關于 SQLite 的更詳細的資料,請參考 SQLite 手冊([http://www.sqlite.org](http://www.sqlite.org))。 ### **23.4 插入數據** 接下來介紹的功能,都通過封裝為 `JZipCode` 類的方法來實現。 首先需要設計郵政編碼表的構成。這里,我們簡單地設計為下面那樣的表。 **表 23.1 郵政編碼檢索表** <table border="1" data-line-num="116 117 118 119 120" width="90%"><thead><tr><th> <p class="表頭單元格">?</p> </th> <th> <p class="表頭單元格">郵政編碼</p> </th> <th> <p class="表頭單元格">都道府縣名</p> </th> <th> <p class="表頭單元格">市區町村名</p> </th> <th> <p class="表頭單元格">町域名</p> </th> <th> <p class="表頭單元格">用于檢索的住址</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格">字段名</p> </td> <td> <p class="表格單元格">code</p> </td> <td> <p class="表格單元格">pref</p> </td> <td> <p class="表格單元格">city</p> </td> <td> <p class="表格單元格">address</p> </td> <td> <p class="表格單元格">alladdress</p> </td> </tr><tr><td> <p class="表格單元格">數據類型</p> </td> <td> <p class="表格單元格">TEXT</p> </td> <td> <p class="表格單元格">TEXT</p> </td> <td> <p class="表格單元格">TEXT</p> </td> <td> <p class="表格單元格">TEXT</p> </td> <td> <p class="表格單元格">TEXT</p> </td> </tr></tbody></table> 為了簡化程序,數據類型都定義為 TEXT 類型,可保存任意長度的字符串數據。 開頭 4 個字段的數據原封不動來自 CSV 文件。最后的“用于檢索的住址”是連接都道府縣名、市區町村名、町域名后的字符串。用住址進行檢索時,可用“東京都港區”2。 2這樣的都道府縣名 + 市區町村名的字符串進行檢索東京都為都道府縣名,港區為市區町村名。——譯者注 我們使用 SQL 的 `CREATE TABLE` 語句創建表。表 23.1 的 SQL 如下所示。 ~~~ CREATE TABLE IF NOT EXISTS zips (code TEXT, pref TEXT, city TEXT, addr TEXT, alladdr TEXT); ~~~ `IF NOT EXISTS` 表示沒有同名表時才創建表。執行上面的 SQL 后就創建了有 5 個 TEXT 類型字段的 zips 表。 代碼清單 23.2 中的 `JZipCode` 類實現了把郵政編碼數據插入到 zips 表的功能(`JZipcode#make_db` 方法)。 **代碼清單 23.2 jzipcode.rb(插入處理)** ~~~ require 'sqlite3' class JZipCode COL_ZIP = 2 COL_PREF = 6 COL_CITY = 7 COL_ADDR = 8 def initialize(dbfile) @dbfile = dbfile end def make_db(zipfile) return if File.exists?(@dbfile) SQLite3::Database.open(@dbfile) do |db| db.execute <<-SQL CREATE TABLE IF NOT EXISTS zips (code TEXT, pref TEXT, city TEXT, addr TEXT, alladdr TEXT) SQL File.open(zipfile, 'r:shift_jis') do |zip| db.execute "BEGIN TRANSACTION" zip.each_line do |line| columns = line.split(/,/).map{|col| col.delete('"')} code = columns[COL_ZIP] pref = columns[COL_PREF] city = columns[COL_CITY] addr = columns[COL_ADDR] all_addr = pref+city+addr db.execute "INSERT INTO zips VALUES (?,?,?,?,?)", [code, pref, city, addr, all_addr] end db.execute "COMMIT TRANSACTION" end end end end ~~~ `COL_ZIP`、`COL_PREF` 等是表示數據是在 CSV 文件的第幾個字段的常量。 `JZipCode.new` 方法的參數為數據庫文件名。`initialize` 方法只是單純將文件名保存到實例變量。`make_db` 方法、`find_by_code` 方法等在打開數據庫時將會用到這個變量。 如果數據庫文件已經存在,程序的初始化已經完成,make_db 方法將不會進行任何操作。 文件不存在時,`SQLite3::Database#open` 方法將會打開新增的數據庫文件,執行 SQL 語句 `CREATE TABLE`。然后打開編碼為 Shift_JIS 的 CSV 文件,使用 `split` 方法以 , 分割。對分割后的各個元素的字符串使用 `delete` 方法刪除”,然后再通過 `map` 方法的塊,將結果保存到變量 `columns` 中。最后執行 `INSERT` 語句,把變量中的都道府縣名、市區町村名、町域名等數據插入到數據庫。 執行 `INSERT` 語句的前后分別有 `BEGIN TRANSACTION` 語句,以及 `COMMIT TRANSACTION` 語句,這是為加快 `INSERT` 語句執行速度常用的方法,在 SQLite3 中也經常使用。 ### **23.5 檢索數據** 接下來,我們來檢索已經保存好的郵政編碼。代碼清單 23.2 的 JZipCode 類定義了 `find_by_code` 方法以及 `find_by_address` 方法。 ~~~ class JZipCode ┊ def find_by_code(code) sql = "SELECT * FROM zips WHERE code = ?" str = "" SQLite3::Database.open(@dbfile) do |db| db.execute(sql, code) do |row| str << sprintf("%s %s", row[0], row[4]) << "\n" end end str end def find_by_address(addr) sql = "SELECT * FROM zips WHERE alladdr LIKE ?" str = "" SQLite3::Database.open(@dbfile) do |db| db.execute(sql, "%#{addr}%") do |row| str << sprintf("%s %s", row[0], row[4]) << "\n" end end str end end ~~~ `find_by_code` 方法以郵政編碼為參數,返回該郵政編碼對應的住址。`find_by_address` 方法恰好相反,以住址為參數,返回包含該住址的郵政編碼。 執行檢索時,與 `INSERT` 語句一樣,使用 `Database#execute` 方法,執行 `SELECT` 語句。通過參數傳遞的值,會置換掉 `WHERE code = ?`、`WHERE alladdr LIKE` 中的條件部分 ? 的值。檢索結果以數組的形式賦值給變量 row,然后再將連接后的字符串保存在變量 `str`。 下面,我們通過 irb 命令,測試一下 `find_by_code` 方法以及 `find_by_address` 方法。 > **執行示例** ~~~ > irb --simple-prompt >> require "./jzipcode" => true >> jzipcode = JZipCode.new("zip.db") => #<JZipCode:0x2c2ab08 @dbfile="zip.db"> >> jzipcode.make_db("KEN_ALL.CSV") => #<SQLite3::Database:0x2c2eb40> >> puts jzipcode.find_by_code('1060031') 1060031 東京都港區西麻布 => nil >> puts jzipcode.find_by_address("東京都渋谷區神") 1500047 東京都渋谷區神山町 1500001 東京都渋谷區神宮前 1500045 東京都渋谷區神泉町 1500041 東京都渋谷區神南 => nil ~~~ 首先,通過 `require "./jzipcode"` 引用 `jzipcode.rb` 的內容。接著,用 `JZipCode.new` 方法創建實例,通過 `make_db` 方法讀取數據。之后,對 `find_by_code` 方法指定郵政編碼,則會輸出對應該郵政編碼的住址。同樣地,對 `find_by_address` 方法指定住址的某部分,則會輸出包含該住址的郵政編碼。 ### **23.6 總結** 本章我們介紹了如何使用 SQLite3 庫提高檢索大量數據時的速度。處理大量數據時,根據實際需要,使用數據庫以及 RubyGems 等現成的類庫,會大大提高程序編寫效率。 數據庫產品中,除了 SQLite3 外,MySQL、PostgreSQL 等也都被廣泛使用。雖然不同的數據庫產品的 SQL 語法等在細節上存在差異,但基本結構是大致相同的。有興趣的讀者可以繼續學習其他數據庫產品。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看