前言
用racket寫腳本休偶。
讀取梁厉、格式化CSV
#lang racket/base
(require racket/file
racket/contract
racket/string)
(define (zip xs ys)
(map list xs ys))
(define 目標(biāo)文件
(string->path "./file/sample.csv"))
(define/contract (讀取文件 文件名)
(-> path? string?)
(file->string 文件名 #:mode 'text))
(define/contract (格式化一行 行 頭)
(-> string? (listof string?) (listof pair?))
(define 行元素列表
(map string-normalize-spaces (string-split 行 ",")))
(zip 頭 行元素列表))
(define/contract (格式化 輸入)
(-> string? (listof hash?))
(define 所有行 (string-split 輸入 "\n"))
(let ([標(biāo)題行 (string-split (car 所有行) ",")]
[內(nèi)容行 (cdr 所有行)])
(map (λ (行) (make-hash (格式化一行 行 標(biāo)題行))) 內(nèi)容行)))
(define/contract (文件->CSV 路徑)
(-> path? (listof hash?))
(格式化 (讀取文件 路徑)))
(displayln (文件->CSV 目標(biāo)文件))
這里處理方式與普通語言沒什么不同,都是從文件中讀取全部內(nèi)容,之后進行格式化词顾。
csv文件內(nèi)容八秃,逗號后面可以跟空格。
name,age
haoren, 10
huairen,20
最后輸出:
(#hash(( age . (10)) (name . (haoren))) #hash(( age . (20)) (name . (huairen))))
SQLite3
racket提供了db
模塊肉盹,可以直接使用sqlite3昔驱。
我們先定義一個結(jié)構(gòu)體,可以簡單把它當(dāng)成表結(jié)構(gòu)上忍。
(struct user
(id name age)
#:transparent)
user有一個id骤肛,它是主鍵,同時窍蓝,它也是自增的腋颠。開始之前,我們需要先連接到一個數(shù)據(jù)庫上它抱。
(define conn (sqlite3-connect #:database db-path
#:mode 'create))
db-path
可以是string或path,連接模式(#:mode
)有三種:'read-only
表示只讀朴艰;'read/write
表示可讀寫观蓄;'create
與'read/write
差不多,當(dāng)它找不到數(shù)據(jù)庫時祠墅,會自動創(chuàng)建侮穿。
建表
(define/contract (create-tables-unless)
(-> (or/c boolean? void?))
(or (table-exists? conn "users")
(local [(define sql "create table users (id integer primary key, name text not null, age int not null)")]
(query-exec conn sql))))
我用table-exists?
判斷是否已經(jīng)建過表了。其實可以直接使用if not exists
語句一次性判斷加創(chuàng)建毁嗦。但是在執(zhí)行時亲茅,racket報錯了。
(create-tables-unless)
; query-exec: near "if": syntax error
; error code: 1
它把if
當(dāng)成racket語句解析了狗准,也難怪克锣,if
本身就是個宏,在執(zhí)行時直接展開了腔长。如果我們換成大寫的IF就沒問題了袭祟。
插入
我們需要插入兩個值,一個name和一個age捞附。
(define/contract (insert-user name age)
(-> string? positive? positive?)
(define insert-sql "insert into users (name, age) values (?, ?)")
(query-exec conn insert-sql name age)
(define last-row-id-sql "select last_insert_rowid()")
(query-value conn last-row-id-sql))
sqlite3需要last_insert_rowid()
函數(shù)去獲取最后得到id巾乳,插入一個記錄后我們返回它的id。
(insert-user "huairen" 20)
2
查詢
query-row和query-list
query-row查詢一行記錄鸟召,返回vectory胆绊;query-list查詢一列記錄,返回list欧募。它們都有一個特點压状,都必須是固定行數(shù)、列數(shù)跟继。query-row查詢結(jié)果必須為一行何缓,query-list查詢結(jié)果必須只有一列肢础。
(query-row conn "select * from users limit 1")
'#(1 "haoren" 10)
(query-list conn "select name from users")
'("haoren" "huairen")
find-by-id
我們偶爾想來個按id查詢。
(define/contract (find-user-by-id id)
(-> positive? (or/c #f user?))
(define result (query-maybe-row conn "select * from users where id = ?" id))
(and result (apply user (vector->list result))))
我們把查詢找到了記錄直接轉(zhuǎn)換成user
碌廓。
(find-user-by-id 2)
(user 2 "huairen" 20)
main.rkt> (find-user-by-id 20)
#f