前言
用racket写脚本。
读取、格式化CSV
#lang racket/base
(require racket/file
racket/contract
racket/string)
(define (zip xs ys)
(map list xs ys))
(define 目标文件
(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 ([标题行 (string-split (car 所有行) ",")]
[内容行 (cdr 所有行)])
(map (λ (行) (make-hash (格式化一行 行 标题行))) 内容行)))
(define/contract (文件->CSV 路径)
(-> path? (listof hash?))
(格式化 (读取文件 路径)))
(displayln (文件->CSV 目标文件))
这里处理方式与普通语言没什么不同,都是从文件中读取全部内容,之后进行格式化。
csv文件内容,逗号后面可以跟空格。
name,age
haoren, 10
huairen,20
最后输出:
(#hash(( age . (10)) (name . (haoren))) #hash(( age . (20)) (name . (huairen))))
SQLite3
racket提供了db
模块,可以直接使用sqlite3。
我们先定义一个结构体,可以简单把它当成表结构。
(struct user
(id name age)
#:transparent)
user有一个id,它是主键,同时,它也是自增的。开始之前,我们需要先连接到一个数据库上。
(define conn (sqlite3-connect #:database db-path
#:mode 'create))
db-path
可以是string或path,连接模式(#:mode
)有三种:'read-only
表示只读;'read/write
表示可读写;'create
与'read/write
差不多,当它找不到数据库时,会自动创建。
建表
(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?
判断是否已经建过表了。其实可以直接使用if not exists
语句一次性判断加创建。但是在执行时,racket报错了。
(create-tables-unless)
; query-exec: near "if": syntax error
; error code: 1
它把if
当成racket语句解析了,也难怪,if
本身就是个宏,在执行时直接展开了。如果我们换成大写的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()
函数去获取最后得到id,插入一个记录后我们返回它的id。
(insert-user "huairen" 20)
2
查询
query-row和query-list
query-row查询一行记录,返回vectory;query-list查询一列记录,返回list。它们都有一个特点,都必须是固定行数、列数。query-row查询结果必须为一行,query-list查询结果必须只有一列。
(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))))
我们把查询找到了记录直接转换成user
。
(find-user-by-id 2)
(user 2 "huairen" 20)
main.rkt> (find-user-by-id 20)
#f