racket脚本日常

前言

用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可以是stringpath,连接模式(#: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

你可能感兴趣的:(racket脚本日常)