4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

wc コマンド for windows

Posted at

tee コマンドに引き続き調子に乗って作った。

bytes はカウントしないように作ったが lenb 関数の存在を知ったのはその後。よって今後、オプション名の変更などするかも知れない。

そのうち github に上げるかもしれないし、上げないかもしれない。

' 名前
'     wc - ファイルの文字数・単語数・行数を表示する
' 
' 書式
'     wc [/c] [/l] [/w] [/L] [/chars] [/lines] [/max-line-length] [/words] [FILE]...
'     wc [/?] [/help] [/v] [/version]
' 
' 説明
'     wc は指定された各 FILE の文字数・空白で区切られた単語の数・行数を数える。 
'     FILE が一つも与えられないと標準入力から読み込む。
'     また FILE が ‘-’ だった場合には、そのファイルには標準入力が用いられる。
' 
'     デフォルトでは、 wc は 3 つ全てを出力する。
'     オプション指定により出力する項目を指定できる。
'     オプションは先に指定したものを取り消すことはできない。
'     したがって ‘wc /chars /words’ は文字数と単語数の両方を出力する。
' 
'     wc は最後の行に各 FILE のカウント数を合計して表示する。
'     結果は、改行数・単語数・文字数の順に表示される。
' 
' オプション
'     /l, /lines
'         改行数だけを出力する。
' 
'     /c, /chars
'         文字数だけを出力する。
' 
'     /w, /words
'         単語数だけを出力する。
' 
'     /L, /max-line-length
'         ファイル中の行の最大長だけを表示する。一つ以上のファイルが指定された場合は、
'         それらのうちでの最大長を表示する (合計ではない)。
' 
'     /help
'         標準出力に使用方法のメッセージを出力して正常終了する。
' 
'     /version
'         標準出力にバージョン情報を出力して正常終了する。
' 
' 注意
'     文字コードが Shift-JIS 以外の場合はうまくカウントできない。
'     改行文字も1文字としてカウントする。例えば CrLf は 2 文字としてカウントする。
'     オリジナルの wc コマンドと違ってバイト数はカウントしない。
' ======================================================================================================================

option explicit

' =================
' option parameters
' =================
dim words, lines, chars, max_line_length
words = true
lines = true
chars = true
max_line_length = false


' ========================
' parse arguments(options)
' ========================
dim arg, i
i = 0
do while i < WScript.Arguments.Count
    arg = WScript.Arguments.Item(i)
    if Left(arg, 1) <> "/" then exit do
    
    if i = 0 then
        chars = false
        words = false
        lines = false
    end if
    
    select case arg
    case "/l", "/lines" lines = true
    case "/c", "/chars" chars = true
    case "/w", "/words" words = true
    case "/L", "/max-line-length" max_line_length = true
    case "/?", "/help"
        call WScript.Echo("USAGE: wc [OPTION]... [FILE]...")
        call WScript.Echo("ファイルの文字数・単語数・行数を表示する")
        call WScript.Quit(0)
    case "/v", "/version"
        call WScript.Echo("wc version 0.1")
        call WScript.Quit(0)
    case else
        call WScript.StdErr.WriteLine("未知のオプション '" & arg & "' が指定されました。")
        call WScript.Quit(1)
    end select
    i = i + 1
loop


' =======================
' parse arguments(inputs)
' =======================
dim fso, files, file
set fso = CreateObject("Scripting.FileSystemObject")
set files = CreateObject("Scripting.Dictionary")
do while i < WScript.Arguments.Count
    arg = WScript.Arguments.Item(i)
    if arg = "-" then
        call files.Add(arg, WScript.Stdin)
    else
        on error resume next
        set file = fso.OpenTextFile(arg)
        if err.number <> 0 then
            call WScript.StdErr.WriteLine( _
                "[" & Err.Number & "]" & Err.description & _
                "'" & fso.GetAbsolutePathName(arg) & "'")
        else
            call files.Add(arg, file)
        end if
        on error goto 0
    end if
    i = i + 1
loop
if files.Count = 0 then call files.Add("-", WScript.Stdin)


' =============================================
' count chars, words, lines and max-line-length
' =============================================
dim results, result
set results = CreateObject("Scripting.Dictionary")
for each file in files
    set result = count(files.Item(file))
    call results.Add(file, result)
next


' =============================
' output results and calc total
' =============================
dim total
set total = new resultset
for each file in results
    set result = results.Item(file)
    total.add_chars(result.chars)
    total.add_words(result.words)
    total.add_lines(result.lines)
    total.add_max_line_length(result.max_line_length)
    if chars then call WScript.Stdout.Write(result.chars & Chr(9))
    if words then call WScript.Stdout.Write(result.words & Chr(9))
    if lines then call WScript.Stdout.Write(result.lines & Chr(9))
    if max_line_length then call WScript.Stdout.Write(result.max_line_length & Chr(9))
    if files.Count > 1 then WScript.Echo(file)
next


' ============
' output total
' ============
if files.Count > 1 then
    if chars then call WScript.Stdout.Write(total.chars & Chr(9))
    if words then call WScript.Stdout.Write(total.words & Chr(9))
    if lines then call WScript.Stdout.Write(total.lines & Chr(9))
    if max_line_length then call WScript.Stdout.Write(total.max_line_length & Chr(9))
    WScript.Echo("total")
end if


' =========================
' define class and function
' =========================
class resultset
    public chars
    public words
    public lines
    public max_line_length
    private sub Class_Initialize
        chars = 0
        words = 0
        lines = 0
        max_line_length = 0
    end sub
    public function init(byval c, byval w, byval l, byval m)
        chars = c
        words = w
        lines = l
        max_line_length = m
        set init = me
    end function
    public function add_chars(byval num)
        chars = chars + num
    end function
    public function add_words(byval num)
        words = words + num
    end function
    public function add_lines(byval num)
        lines = lines + num
    end function
    public function add_max_line_length(byval num)
        max_line_length = max_line_length + num
    end function
end class

function count(byval stream)
    dim result
    set result = new resultset
    call result.init(0, 0, 0, 0)
    
    dim ch, before, width
    before = " "
    width = 0
    do while not stream.AtEndOfStream
        ch = stream.Read(1)
        width = width + 1
        
        ' count chars
        call result.add_chars(1)
        
        ' count words
        if Asc(before) <= 32 and (Asc(ch) < 0 or 32 < Asc(ch)) then
            call result.add_words(1)
        end if
        
        ' count lines, and line-length
        if before = vbLf then
            call result.add_lines(1)
            if result.max_line_length < width then result.max_line_length = width
            width = 0
        elseif before = vbCr and ch <> vbLf then
            call result.add_lines(1)
            if result.max_line_length < width then result.max_line_length = width
            width = 0
        end if
        before = ch
    loop
    
    if width > result.max_line_length then result.max_line_length = width
    if result.chars > 0 then call result.add_lines(1)
    
    set count = result
end function
4
1
0

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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?