Deno: 標準入力を読んで行ごとに処理

簡易版

お手軽に済ませたいならこれでよいっぽい。

参考: std@0.61.0 | Deno

// my_simple_cat.ts

import { readLines } from "https://deno.land/std/io/mod.ts";

for await (let line of readLines(Deno.stdin)) {
  console.log(line);
}
$ cat my_simple_cat.ts | deno run my_simple_cat.ts | cat -A
import { readLines } from "https://deno.land/std/io/mod.ts";$
$
for await (let line of readLines(Deno.stdin)) {$
  console.log(line);$
}$
$

改行を変化させないようにしたもの

上記の簡易版では改行の情報が失われて困るので、そうならないようにしたもの。

  • 改行が LF または CRLF であることを前提にしています。
  • 文字エンコーディングUTF-8 であることを前提にしています。
  • パフォーマンスについては調べていません。 もっと効率のよい書き方はあると思います。
    • Deno.Buffer とか使うとよい?
// my_cat.ts

const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
const LF = "\n".charCodeAt(0);

class ByteBuffer {
  bytes: number[];

  constructor() {
    this.bytes = [];
  }

  push(val: number) {
    this.bytes.push(val);
  }

  toLine() {
    return textDecoder.decode(
      new Uint8Array(this.bytes),
    );
  }
}

class StdinReader {
  buf: ByteBuffer;

  constructor() {
    this.buf = new ByteBuffer();
  }

  async read(
    fn: (line: string) => void,
  ) {
    const readBuf = new Uint8Array(1024);

    const numRead = await Deno.stdin.read(readBuf);
    if (numRead === null) {
      return null;
    }

    for (let i = 0; i < numRead; i++) {
      const val = readBuf[i];
      this.buf.push(val);

      if (val === LF) {
        fn(this.buf.toLine());
        this.buf = new ByteBuffer();
      }
    }

    return numRead;
  }

  async eachLine(fn: (line: string) => void) {
    while (true) {
      const numRead = await this.read(fn);

      if (numRead === null) {
        fn(this.buf.toLine());
        break;
      }
    }

    return null;
  }
}

const print = (str: string) => {
  Deno.stdout.writeSync(
    textEncoder.encode(str),
  );
};

new StdinReader().eachLine((line) => print(line));

なファイルで確認:

$ export PS1='--------\n$ '
--------
$ cat end_with_newline.txt 
あいうえお
aa
bb
--------
$ cat -A end_with_newline.txt 
M-cM-^AM-^BM-cM-^AM-^DM-cM-^AM-^FM-cM-^AM-^HM-cM-^AM-^J^M$
aa^M$
bb^M$
--------
$ cat end_with_newline.txt | deno run my_cat.ts | cat -A
M-cM-^AM-^BM-cM-^AM-^DM-cM-^AM-^FM-cM-^AM-^HM-cM-^AM-^J^M$
aa^M$
bb^M$
--------
$ 

なファイルで確認:

$ export PS1='--------\n$ '
--------
$ cat end_without_newline.txt 
あいうえお
aa
bb--------
$ cat -A end_without_newline.txt 
M-cM-^AM-^BM-cM-^AM-^DM-cM-^AM-^FM-cM-^AM-^HM-cM-^AM-^J^M$
aa^M$
bb--------
$ cat end_without_newline.txt | deno run my_cat.ts | cat -A
M-cM-^AM-^BM-cM-^AM-^DM-cM-^AM-^FM-cM-^AM-^HM-cM-^AM-^J^M$
aa^M$
bb--------
$ 

バージョン

$ deno -V
deno 1.2.0

参考

この記事を読んだ人はこちらも(たぶん)読んでいます

memo88.hatenablog.com