LoginSignup
2
2

More than 5 years have passed since last update.

23分クッキング: awk のようなものを作る

Last updated at Posted at 2015-02-06

#!/usr/local/bin/ros でそのまま通るはずと思っていたんですがそう簡単にはいかないようで。snさん今度使い方教えてください。

使用例:

example.lisp
;; cat data | /usr/local/bin/sbcl --load example.lisp -
;; /usr/local/bin/sbcl --load example.lisp data

(ql:quickload :awklike)
(use-package :awklike)

(awk BEGIN
  (print (cdr sb-ext:*posix-argv*))
  (print "hello!"))

(awk |-data|
  (print $2))

(main (cdr sb-ext:*posix-argv*))
(exit)
data
2010-data 100
2011-data 110
2012-data 120
2013-data 130
2014-data 140
output
("-") 
"hello!" 
"100" 
"110" 
"120" 
"130" 
"140"

実装:

#|
  This file is a part of awklike project.
  Copyright (c) 2015 Masataro Asai (guicho2.71828@gmail.com)
|#

(in-package :cl-user)
(defpackage awklike
  (:use :cl :optima :optima.ppcre :alexandria :iterate :cl-ppcre :lisp-namespace)
  (:export
   #:$0
   #:awk
   #:main
   #:BEGIN
   #:END
   #:UNBOUND-MATCHER
   #:SYMBOL-MATCHER
   #:MATCHER-BOUNDP
   #:matcher))
(in-package :awklike)

;; blah blah blah.

(define-namespace matcher (function (string list) t))

(eval-when (:compile-toplevel :load-toplevel :execute)
  ;; CLHS says CALL-ARGUMENTS-LIMIT is larger than 50
  (defvar *max-column* 50)
  (defmacro define-$-macros ()
    `(progn
       ,@(iter (for i from 1 below *max-column*)
               (for sym = (symbolicate "$" (princ-to-string i)))
               (appending
                `((define-symbol-macro ,sym
                      (nth ,(1- i) awk-arguments))
                  (export ',sym))))))
  (defmacro awk (key &body body)
    `(setf
      (symbol-matcher ',key)
      ,(match (symbol-name key)
         ((or "BEGIN" "END")
          `(lambda ($0)
             (declare (ignorable $0))
             (let ((awk-arguments (split "\\s+" $0)))
               (declare (ignorable awk-arguments))
               ,@body)))
         (regex
          `(lambda ($0)
             (declare (ignorable $0))
             (when (scan ,(format nil ".*~a.*" regex) $0)
               (let ((awk-arguments (split "\\s+" $0)))
                 (declare (ignorable awk-arguments))
                 ,@body))))))))

(define-$-macros)

(awk BEGIN)
(awk END)

(defun main (&optional (in-files '("-")))
  (iter (for in in in-files)
        (match in
          ("-"
           (read-loop *standard-input*))
          ((string)
           (with-open-file (s in)
             (read-loop s))))))

(defun read-loop (s)
  (funcall (symbol-matcher 'begin) nil)
  (iter (for line = (read-line s nil nil))
        (while line)
        (search-match line))
  (funcall (symbol-matcher 'end) nil))

(defun search-match (line)
  (iter (for (key fn) in-hashtable *matcher-table*)
        (unless (or (eq key 'begin) (eq key 'end))
          (funcall fn line))))
2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2