美文网首页Racket小白
racket脚本日常

racket脚本日常

作者: XGLey | 来源:发表于2018-03-17 20:47 被阅读97次

    前言

    用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脚本日常

        本文链接:https://www.haomeiwen.com/subject/rztsqftx.html