Python技术迷

写一个 Python 逻辑,计算一个文件中的大写字母数量

写这篇东西啊,其实是因为我昨天下班回家路上,手机快没电了还硬要看一个 Python 群的聊天,有人突然问:怎么用 Python 算一个文件里面有多少大写字母。我当时心里一笑,这不是很简单么,随手写个几行就完事,但转念一想,这个问题要是真写清楚,也挺有意思。因为简单背后还有挺多小细节的,顺手整理出来,也许有人能用得上。

先聊点场景

我举个生活化的例子哈。比如你拿到一份日志文件,几百 M,上面一大堆字母、符号,夹杂着大写、小写,你老板说:我只想知道这里面大写字母的数量,比如看看异常信息是不是一堆大写开头。你要是肉眼数,估计数到怀疑人生。这个时候 Python 的优势就出来了,写个脚本,几秒钟跑完。

最朴素的办法

最直觉的办法,就是打开文件,一个字符一个字符看,判断是不是大写。Python 里面 str.isupper() 这个方法就挺好用的。

defcount_uppercase(filepath):
    count = 0
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
for ch in line:
if ch.isupper():
                    count += 1
return count

print(count_uppercase("test.txt"))

这段代码其实已经能解决问题了。它逐行读取,逐个字符判断,如果是大写字母,就把计数器加一。简单直接,逻辑一目了然。

但是事情没那么简单

上面这种写法,用在小文件上挺好。但要是文件特别大呢?比如那种 GB 级日志,如果你一次性读到内存里面,内存可能直接爆掉。所以我在代码里面用了 for line in f,这样是逐行读的,内存压力小很多。

再来考虑一个问题:什么算大写?isupper() 会认为 Ä 这种带音标的拉丁字母也是大写。你要是只想统计 A-Z,那就要换种写法,用 ASCII 范围判断。

defcount_uppercase_ascii(filepath):
    count = 0
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
for ch in line:
if"A" <= ch <= "Z":
                    count += 1
return count

这就规避了语言和地区的问题,更精确。

用正则更快一点

有同事跟我说,用正则其实更快,写起来也简洁。

import re

defcount_uppercase_regex(filepath):
    pattern = re.compile(r"[A-Z]")
    count = 0
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
            count += len(pattern.findall(line))
return count

这种方式是用正则一次性把一行里面的大写字母都找出来,然后用 len 数一数,效率比逐个字符判断要高一点。但正则会稍微消耗点性能,在大文件里可能差别不大,不过代码看起来干净。

性能和优化的小八卦

这事我之前真试过,当时在公司写个小脚本,统计了一个接近 1G 的日志文件。逐字符和正则跑下来,正则版快了大概 20%,差距不是特别大。反而最大的性能提升,来自于 不要一次性读整个文件,而是逐行或者分块读取。

如果追求极限,还可以用 mmap,把文件映射到内存,然后一边扫描一边统计。不过那就没必要贴代码了,有点过于硬核,平常用不到。

错误处理别忘了

说到这儿,还有一个坑。文件可能不是 UTF-8 编码,可能是 GBK,或者里面有点脏数据。这个时候直接 open 可能报错。保险点的写法,可以这样:

with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
    ...

加上 errors="ignore",有些无法解码的字符就会被跳过,不至于程序崩掉。

写成命令行工具

要是你老是要用这个统计,不如写成一个小脚本,直接命令行运行。

import argparse

defcount_uppercase_ascii(filepath):
    count = 0
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
for ch in line:
if"A" <= ch <= "Z":
                    count += 1
return count

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="统计文件中的大写字母数量")
    parser.add_argument("file", help="文件路径")
    args = parser.parse_args()
    result = count_uppercase_ascii(args.file)
    print(f"大写字母数量: {result}")

保存成 count_upper.py,然后在命令行里敲:

python count_upper.py test.txt

立马给你结果。这个脚本还能随手加点扩展,比如统计小写,统计数字,都差不多。

其实这个逻辑不止能用来统计字母。你完全可以扩展一下,统计数字的个数,或者统计某个特定字符的频率。比如写个统计字频的工具,分析小说里面哪个词出现得最多,这种应用场景也挺多的。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领