|
1 | 1 | import argparse |
| 2 | +import glob |
2 | 3 |
|
3 | 4 | def count_file(filename): |
| 5 | + line_count = 0 |
| 6 | + word_count = 0 |
| 7 | + byte_count = 0 |
| 8 | + |
4 | 9 | try: |
5 | | - with open(filename, "r", encoding="utf-8") as f: |
| 10 | + with open(filename, "rb") as f: |
6 | 11 | content = f.read() |
7 | | - lines = content.count("\n") |
8 | | - words = len(content.split()) |
9 | | - bytes_ = len(content.encode("utf-8")) |
10 | | - return lines, words, bytes_ |
| 12 | + byte_count = len(content) |
| 13 | + text = content.decode("utf-8", errors="replace") |
| 14 | + lines = text.splitlines() |
| 15 | + line_count = len(lines) |
| 16 | + word_count = sum(len(line.split()) for line in lines) |
| 17 | + |
| 18 | + return (line_count, word_count, byte_count) |
11 | 19 | except FileNotFoundError: |
12 | 20 | print(f"wc: {filename}: No such file or directory") |
13 | | - return 0, 0, 0 |
| 21 | + return None |
14 | 22 |
|
15 | 23 | def main(): |
16 | 24 | parser = argparse.ArgumentParser(description="Python version of wc") |
17 | | - parser.add_argument("files", nargs="+", help="Files to count") |
| 25 | + parser.add_argument("-l", action="store_true", help="Count lines") |
| 26 | + parser.add_argument("-w", action="store_true", help="Count words") |
| 27 | + parser.add_argument("-c", action="store_true", help="Count bytes") |
| 28 | + parser.add_argument("files", nargs="+", help="Files to read (supports wildcards)") |
18 | 29 | args = parser.parse_args() |
19 | 30 |
|
20 | | - for filename in args.files: |
21 | | - lines, words, bytes_ = count_file(filename) |
22 | | - print(f"{lines:7} {words:7} {bytes_:7} {filename}") |
| 31 | + # If no flag is given, show all |
| 32 | + show_lines = args.l |
| 33 | + show_words = args.w |
| 34 | + show_bytes = args.c |
| 35 | + if not (show_lines or show_words or show_bytes): |
| 36 | + show_lines = show_words = show_bytes = True |
| 37 | + |
| 38 | + file_list = [] |
| 39 | + for pattern in args.files: |
| 40 | + matched = glob.glob(pattern) |
| 41 | + if matched: |
| 42 | + file_list.extend(matched) |
| 43 | + else: |
| 44 | + file_list.append(pattern) |
| 45 | + |
| 46 | + total_lines = total_words = total_bytes = 0 |
| 47 | + for filename in file_list: |
| 48 | + result = count_file(filename) |
| 49 | + if result is None: |
| 50 | + continue |
| 51 | + lines, words, bytes_ = result |
| 52 | + total_lines += lines |
| 53 | + total_words += words |
| 54 | + total_bytes += bytes_ |
| 55 | + |
| 56 | + output = [] |
| 57 | + if show_lines: |
| 58 | + output.append(f"{lines:7}") |
| 59 | + if show_words: |
| 60 | + output.append(f"{words:7}") |
| 61 | + if show_bytes: |
| 62 | + output.append(f"{bytes_:7}") |
| 63 | + output.append(filename) |
| 64 | + print(" ".join(output)) |
| 65 | + |
| 66 | + if len(file_list) > 1: |
| 67 | + output = [] |
| 68 | + if show_lines: |
| 69 | + output.append(f"{total_lines:7}") |
| 70 | + if show_words: |
| 71 | + output.append(f"{total_words:7}") |
| 72 | + if show_bytes: |
| 73 | + output.append(f"{total_bytes:7}") |
| 74 | + output.append("total") |
| 75 | + print(" ".join(output)) |
23 | 76 |
|
24 | 77 | if __name__ == "__main__": |
25 | 78 | main() |
0 commit comments