Skip to content

Commit ebd5f71

Browse files
committed
Refactor wc into reusable function and fix line counting to match Unix wc
1 parent 4471a05 commit ebd5f71

File tree

1 file changed

+29
-44
lines changed
  • implement-shell-tools/wc

1 file changed

+29
-44
lines changed

implement-shell-tools/wc/wc.py

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44

55

66
def main():
7-
# --------------------------------------------------------
8-
# Set up argparse
9-
# --------------------------------------------------------
107
parser= argparse.ArgumentParser(
118
prog="wc",
129
description ="wc command implementation in python"
@@ -20,74 +17,62 @@ def main():
2017

2118
args = parser.parse_args()
2219

23-
# --------------------------------------------------------
24-
# Ensures at least one path exists
25-
# --------------------------------------------------------
2620
if len(args.paths) == 0:
2721
print("wc: no file specified", file=sys.stderr)
2822
sys.exit(1)
2923

3024
totals= {"lines": 0, "words": 0, "chars": 0}
3125

32-
# --------------------------------------------------------
33-
# Loop over each file path and process it
34-
# --------------------------------------------------------
26+
no_flags = not args.l and not args.w and not args.c
27+
width = 7
28+
29+
def format_output(counts, label):
30+
if no_flags:
31+
return f"{counts['lines']:> {width}}{counts['words']:>{width}}{counts['chars']:>{width}} {label}"
32+
33+
parts = []
34+
if args.l:
35+
parts.append(f"{counts['lines']:>{width}}")
36+
if args.w:
37+
parts.append(f"{counts['words']:>{width}}")
38+
if args.c:
39+
parts.append(f"{counts['chars']:>{width}}")
40+
41+
return f"{''.join(parts)} {label}"
42+
had_error = False
43+
3544
for file_path in args.paths:
3645
try:
37-
with open(file_path, "r", encoding="utf-8") as f:
38-
content = f.read()
46+
with open(file_path, "rb") as f:
47+
data = f.read()
3948
except OSError as err:
4049
print(f"wc: cannot read file'{file_path}': {err}", file=sys.stderr)
50+
had_error = True
4151
continue
4252

43-
# --------------------------------------------------------
44-
# Count values
45-
# --------------------------------------------------------
46-
line_count = len(content.split("\n"))
53+
content = data.decode("utf-8", errors="replace")
54+
55+
line_count = content.count("\n")
4756

4857
words = [w for w in re.split(r"\s+", content) if w]
4958
word_count = len(words)
59+
char_count = len(data)
5060

51-
char_count = len(content)
61+
counts = {"lines": line_count, "words": word_count, "chars":char_count}
5262

5363
totals["lines"] += line_count
5464
totals["words"] += word_count
5565
totals["chars"] +=char_count
5666

57-
# --------------------------------------------------------
58-
# Decide what to print based on flags
59-
# --------------------------------------------------------
60-
no_flags = not args.l and not args.w and not args.c
67+
print(format_output(counts, file_path))
6168

62-
if no_flags:
63-
print(f"{line_count} {word_count} {char_count} {file_path}")
64-
continue
65-
66-
if args.l:
67-
print(f"{line_count} {file_path}" )
68-
69-
if args.w:
70-
print(f"{word_count} {file_path}")
71-
72-
if args.c:
73-
print(f"{char_count} {file_path}")
74-
75-
76-
# --------------------------------------------------------
77-
# Print totals if there are multiple files
78-
# --------------------------------------------------------
7969
if len(args.paths) > 1:
8070
no_flags = not args.l and not args.w and not args.c
8171

8272
if no_flags:
83-
print(f"{totals['lines']} {totals['words']} {totals['chars']} total")
73+
print(format_output(totals, "total"))
8474

85-
if args.l:
86-
print(f"{totals['lines']} total")
87-
if args.w:
88-
print(f"{totals['words']} total")
89-
if args.c:
90-
print(f"{totals['chars']} total")
75+
sys.exit(1 if had_error else 0)
9176

9277
if __name__ == "__main__":
9378
main()

0 commit comments

Comments
 (0)