Metadata-Version: 2.1
Name: hufengguo
Version: 1.3.7
Summary: A small example package from Hufengguo, CUC
Author-email: cucialhu <cuchufengguo@163.com>
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/markdown
Requires-Dist: chardet<5.0.0; python_version == "3.6"
Requires-Dist: chardet>=5.0.0; python_version > "3.6"
Requires-Dist: jieba>=0.42.1
Provides-Extra: pdf
Requires-Dist: pymupdf>1.19.3; python_version >= "3.7" and extra == "pdf"
Requires-Dist: pymupdf<=1.19.3; python_version == "3.6" and extra == "pdf"
Requires-Dist: pypdf>4.3.1; python_version > "3.7" and extra == "pdf"
Requires-Dist: pypdf<=4.3.1; python_version <= "3.7" and extra == "pdf"
Provides-Extra: gui
Requires-Dist: windnd; platform_system == "Windows" and extra == "gui"
Provides-Extra: all
Requires-Dist: chardet<5.0.0; python_version == "3.6" and extra == "all"
Requires-Dist: chardet>=5.0.0; python_version > "3.6" and extra == "all"
Requires-Dist: jieba>=0.42.1; extra == "all"
Requires-Dist: pymupdf>1.19.3; python_version >= "3.7" and extra == "all"
Requires-Dist: pymupdf<=1.19.3; python_version == "3.6" and extra == "all"
Requires-Dist: pypdf>4.3.1; python_version > "3.7" and extra == "all"
Requires-Dist: pypdf<=4.3.1; python_version <= "3.7" and extra == "all"
Requires-Dist: windnd; platform_system == "Windows" and extra == "all"

# 扩展库介绍

这是中国传媒大学胡凤国老师上课分享的自定义函数库，最初包含几个常用的文本处理及目录操作函数，后来又陆续添加了其它功能。发布本扩展库主要是方便上课学生练习Python程序，顺便分享给其他需要的Pythoner。

刚学会发布扩展库，PyPI很多东西还不熟，代码力求多平台通用，已经在Windows下进行了测试，Linux和mac下可能存在一些问题，如有问题，请多提宝贵意见。

最近更新日期：2026年8月22日，主要是修正了my_path2path函数的一个小BUG。


# 安装说明

## 环境要求
- **所需Python版本**：Python 3.6+
- **推荐Python版本**：Python 3.8+

## 初次安装

如果电脑上安装了多个版本的Python，pip命令安装扩展库时需要指定Python软件的版本号，例如：pip3.6、pip3.8、pip3.9、pip3.14、……、等等。如果只安装了一个版本的Python软件，那么，可以直接写pip不用带Python的版本号。下面的安装命令假设电脑上只安装了一个版本的Python软件。

### 仅安装核心模块
```cmd
pip install hufengguo
```

### 安装所有模块
```cmd
pip install "hufengguo[all]"
```

### 安装 GUI 处理功能
```cmd
pip install "hufengguo[gui]"
```

### 安装 PDF 处理功能
```cmd
pip install "hufengguo[pdf]"
```

## 更新安装
```cmd
pip install -U 所需模块
```


# 用法说明

基本用法见胡凤国老师的上课教材：《Python程序设计（基于计算思维和新文科建设）》，ISBN：9787121435577，胡凤国，电子工业出版社，2022年6月。

这里举一些简单的例子。


## 产生1到100之内的素数

```python
# 导入
from hufengguo import isprime

# 产生素数列表
x = [i for i in range(101) if isprime(i)]

# 输出
print(x)
```

## 去掉多行文本中的空白行和每行首尾空白符

```python
# 导入
from hufengguo import remove_white_from_text

# 赋值
s = "\t\n\n  今天是个好日子，\t\n  \n  \t心想的事儿都能成。\n \n\n"

# 去掉多行文本中的空白行和每行首尾空白
print("="*10)
print(remove_white_from_text(s))
print("="*10)

# 去掉去掉多行文本中的每行首尾空白、前面空白，第一行非空内容之后多个空白行保留一个
print(remove_white_from_text(s, keep_one_empty_line=True))
print("="*10)
```


## 随机生成若干个长度介于指定范围内的密码字符串
```python
# 导入
from hufengguo import gen_pwd

# 产生一个长度为6的密码，密码字符包含大小写英文字母和数字
print(gen_pwd(6))

# 产生一个长度为在4到8之间的密码（含4和8），密码字符包含大小写英文字母和数字
print(gen_pwd(4, 8))

# 产生一个长度为在4到8之间的密码（含4和8），密码字符包含大小写英文字母、数字和标点符号
print(gen_pwd(4, 8, punct=True))

# 产生一个长度为在4到8之间的密码（含4和8），密码字符包含大小写英文字母
print(gen_pwd(4, 8, digit=False))

# 产生一个长度为在4到8之间的密码（含4和8），密码字符包含大写英文字母和数字
print(gen_pwd(4, 8, lower=False))

# 产生一个长度为在4到8之间的密码（含4和8），密码字符包含小写英文字母和数字
print(gen_pwd(4, 8, upper=False))

# 产生5个长度为在4到8之间的密码（含4和8）
print(gen_pwd(4, 8, count=5))

# 产生5个长度为在4到8之间的密码（含4和8），所有密码等长
print(gen_pwd(4, 8, count=5, samelen=True))
```


## 数字与汉字读法互转

本库采用我国传统数学的大数体系：零一二三四五六七八九十百千万亿兆京垓秭穰沟涧正载极。从十开始逢十进位；从万开始逢万进位，1兆等于1万亿（10的12次方），1京等于1万兆（10的16次方），……，1极等于1万载（10的48次方），传统大数体系可以表示长达96位数字。本库既支持长达96位数字的传统大数体系，又支持目前只通过万和亿循环的大数表示方法。

```python
# 导入
from hufengguo import digit2hanzi, hanzi2digit

# 汉字转数字
print(hanzi2digit("一百二十三"))
print(hanzi2digit("壹佰贰拾叁"))
print(hanzi2digit("三兆"))
print(hanzi2digit("三万亿"))
print(hanzi2digit("一京"))
print(hanzi2digit("一亿亿"))
print(hanzi2digit("万"))       # 输出-1，因为它不是正常的数字读法
print(hanzi2digit("千"))       # 输出-1，因为它不是正常的数字读法
print(hanzi2digit("亿"))       # 输出-1，因为它不是正常的数字读法

# 非负整数转汉字
# daxieflag=True表示汉字读法用人民币金额大写的形式给出结果
# wanyiflag=True表示沿用目前的读法，万亿不写为兆，亿亿不写为京，……
print(digit2hanzi(123))
print(digit2hanzi(123, daxieflag=True))
print(digit2hanzi(3*10**12))
print(digit2hanzi(3*10**12, wanyiflag=True))
print(digit2hanzi(1234500000000))
print(digit2hanzi(1234500000000, wanyiflag=True))
print(digit2hanzi(12345000000000000))
print(digit2hanzi(12345000000000000, wanyiflag=True))
print(digit2hanzi(0))
print(digit2hanzi(-1))     # 参数非法，输出空字符串
```


## 人民币金额的正常汉字写法与大写写法互转

```python
# 导入
from hufengguo import xiao2da, da2xiao

# 转换
print(xiao2da("一万二千三百零六"))
print(da2xiao("壹万贰仟叁佰零陆"))
```


## 分节格式化数字

```python
# 导入
from hufengguo import fenjie_number

# 分节格式化操作
print(fenjie_number(12345678901, group=3))           # 3位一组，半角逗号隔开
print(fenjie_number(12345678901, group=3, sep="_"))  # 3位一组，半角下划线隔开
print(fenjie_number(12345678901))                    # 4位一组，半角空格隔开
print(fenjie_number(12345678901, group=4))           # 4位一组，半角空格隔开
print(fenjie_number(12345678901, group=5, sep=","))  # 5位一组，半角逗号隔开
print(fenjie_number(-1234567))                       # 4位一组，半角空格隔开
```

注意：分节格式化数字的函数 fenjie_number 最初发布时包含两个m，形式是 fenjie_nummber ，现予以纠正，变成一个m的函数，同时为了保证兼容性，两个m的函数将继续保留。

```python
# 导入
from hufengguo import fenjie_nummber

# 分节格式化操作
print(fenjie_nummber(12345678901, group=3))           # 3位一组，半角逗号隔开
print(fenjie_nummber(12345678901, group=3, sep="_"))  # 3位一组，半角下划线隔开
print(fenjie_nummber(12345678901))                    # 4位一组，半角空格隔开
print(fenjie_nummber(12345678901, group=4))           # 4位一组，半角空格隔开
print(fenjie_nummber(12345678901, group=5, sep=","))  # 5位一组，半角逗号隔开
print(fenjie_nummber(-1234567))                       # 4位一组，半角空格隔开
```



## 读写文本文件

本库提供了两个函数来帮我们方便地读写文本文件。

函数 my_read_from_txtfile 会自动判断文本文件编码并读取其内容为字符串，它调用了chardet的自动判断文件编码功能；

函数 my_write_to_txtfile 会根据指定的文件名、字符串和指定的编码生成文本文件，编码支持Windows 10的记事本所自带的五种编码，默认编码是带有BOM的UTF-8编码；当文件所在目录不存在时，能自动创建文件所在目录。

这两个文件均支持文件名末尾带有空格的情况，我们用Python内置的open函数来读写文本文件是不支持这种情况的。

```python
# 导入
from hufengguo import my_read_from_txtfile, my_write_to_txtfile

# 赋值
fn = r"abc \xyz "   # 注意目录名和文件名最后均有空格

# 生成文件，它会自动创建文件所在的目录
# 默认生成的文本文件编码是带有BOM的UTF-8编码，我们生成文件时可以用encoding参数指定文本文件的编码
my_write_to_txtfile(fn, "今天天气哈哈哈", encoding="gb18030")

# 读取文件，它会自动判定文本文件的编码
print(f"文件“{fn}”内容是：{my_read_from_txtfile(fn)}")
```

注意，在Windows下，这个生成的文件用os.path.exists是检测不到它的存在的，这个生成的文件用os.remove是删不掉的，手动删除也删不掉。与此类似，这个生成的文件所在目录用shutil.rmtree是删不掉的，手动删除也删不掉。

用本库提供的其它函数可以判定这一类文件的存在性，也可以删除这一类的文件和目录，后面会举例。


## 判断文件和目录的存在性的通用函数

前面提到，有一些文件名和目录名最后带有空格，它们的存在性用os.path.exists是检测不到，它们用os.remove和shutil.rmtree删不掉，本库提供了三个函数来做这个事情，这三个函数是通用的，同时适用于普通文件和目录，也适用于名称最后带有空格的文件和目录。

```python
# 导入
from os.path import dirname, exists
from os import remove
from shutil import rmtree
from hufengguo import my_write_to_txtfile, make_dir_exists, my_exists, my_os_remove, my_shutil_rmtree

# 赋值
fn = r"abc \xyz "   # 注意目录名和文件名最后均有空格
d = dirname(fn)

# 生成目录和文件
print(make_dir_exists(d))
my_write_to_txtfile(fn, "今天天气哈哈哈")

# 判断文件和目录的存在性
print(f"用os.path.exists判定文件“{fn}”是否存在：{exists(fn)}")
print(f"用os.path.exists判定文件所在目录“{d}”是否存在：{exists(d)}")
print(fn, my_exists(fn))
print(d, my_exists(d))

# 删除文件和目录
try:
    remove(fn)
except Exception as e:
    print(f"用os.remove删除文件“{fn}”失败，错误信息是：{e}")
print(my_os_remove(fn))

try:
    rmtree(d)
except Exception as e:
    print(f"用shutil.rmtree删除文件所在目录“{d}”失败，错误信息是：{e}")
print(my_shutil_rmtree(d))
```

将来大家遇到文件名或目录名最后有空格手动删除不了的情况时，可以考虑使用本库提供的函数来帮你删掉。如果有特殊需要生成带空格的目录名和文件名，也可以使用本库提供的相应函数来达到目的。


## 获取当前Python程序文件所在的路径及相关路径

程序运行过程中，当前路径可能会变化，但Python程序文件所在的路径不会变化，这里给出的函数 my_abspath 能获取当前Python程序文件所在路径的绝对路径形式，以该路径为基础的一些路径也能获取。该函数的功能还不止这些，具体请参考下面的代码注释。

```python
# 导入
from hufengguo import my_abspath

# 输出当前Python程序所在目录的绝对路径，注意，结果不一定是当前目录
# 如果是在Jupyter Notebook的单元格中运行，则获取当前Jupyter Notebook文档所在的绝对路径
# 如果是在Python文件打包成的exe文件中运行，则获取当前exe文件所在的绝对路径
# 为简单起见，后面的测试代码只说当前Python程序所在目录
p = my_abspath()
print([p])

# 输出当前Python程序所在目录下的“test.txt”的绝对路径
print(my_abspath(r"test.txt"))

# 输出当前Python程序所在目录下的上级目录下的“test.txt”的绝对路径
print(my_abspath(r"..\test.txt"))

# 输出当前Python程序所在目录下的“test ”的绝对路径
# 这里故意在最后加了一个空格
# Python的os.path.abspath会自动删掉最后的空格
print([my_abspath(r"test ")])
```


## 获取Windows桌面的全路径名

程序运行过程中，我们有时候会希望读取桌面的文件或者把文件生成到桌面上，本库提供了 my_desktop_path 函数来获取Windows桌面及相关的全路径名。

```python
# 导入
from hufengguo import my_desktop_path

# 获取桌面的全路径名
p = my_desktop_path()
print(p)

# 获取桌面或其子孙目录中的文件的全路径名
p = my_desktop_path(r"abc\test.txt")
print(p)
```


## 测试文件只读属性三件套

下面这三个函数能判断文件的只读属性、为文件添加只读属性和去除文件的只读属性。

```python
# 代入
from hufengguo import my_read_from_txtfile, my_write_to_txtfile, file_is_readonly, file_add_readonly, file_remove_readonly, my_os_remove

# 赋值
fn = "test12345.txt"

# 生成文件
my_write_to_txtfile(fn, "今天天气哈哈哈")
print(my_read_from_txtfile(fn))

# 第1次判断文件是否具有只读属性
print(file_is_readonly(fn))   # False

# 为文件添加只读属性
print(file_add_readonly(fn))

# 第2次判断文件是否具有只读属性
print(file_is_readonly(fn))   # True

# 取消只读
print(file_remove_readonly(fn))

# 第3次判断文件是否具有只读属性
print(file_is_readonly(fn))   # False

# 删除测试时生成的文件
print(my_os_remove(fn))
```


## 在目录及子目录下查找文件

```python
# 导入
from hufengguo import find_files_walk, my_abspath

# 赋值，相对路径（相对于脚本目录）和绝对路径都行
# 如果p是相对路径，查找到的文件都是相对路径
# 如果p是绝对路径，查找到的文件都是绝对路径
p = r"abc"
# p = my_abspath(r"abc")

# 查找所有文件
files = find_files_walk(p)
print(*files, sep="\n")

print()

# 查找Word文件
files = find_files_walk(p, [".doc", ".docx"])
print(*files, sep="\n")

print()

# 查找文本文件
files = find_files_walk(p, [".txt"])
print(*files, sep="\n")

print()

# 查找没有扩展名的文件
files = find_files_walk(p, [""])
print(*files, sep="\n")
```


## 复制一个目录及子目录下指定类型的文件到另一个目录

本库提供的函数支持扁平化复制和保持目录结构复制。

```python
# 导入
from hufengguo import copytree_filtered

# 复制
pathin, pathout1, pathout2 = r"in", r"out1", r"out1"
filetypes = [".doc", ".docx"]
copytree_filtered(pathin, pathout1, filetypes)                 # 扁平化复制目录树中指定类型的文件
copytree_filtered(pathin, pathout2, filetypes, flatten=False)  # 保持目录结构复制目录树中指定类型的文件
```


## 目录对目录操作示例

下面的代码把多对多的目录操作变成了单对单的文件操作，我们只需要写一个单对单的文件处理函数就好了。

```python
# 导入
from hufengguo import my_read_from_txtfile, my_write_to_txtfile, remove_white_from_text, my_path2path

# 自定义函数：单对单文件操作示例，去掉文本文件中的空白行和每行首尾空白
def myfunc(fnin, fnout):
    s = my_read_from_txtfile(fnin)  # 读取
    t = remove_white_from_text(s)   # 操作
    my_write_to_txtfile(fnout, t)   # 写入

# 赋值
pathin = r"in"
filetypelist = [".txt"]
pathout = "out"
func = myfunc
outext = None

# 操作
my_path2path(pathin, filetypelist, pathout, func, outext)
```


## 分词操作

jieba库使用简单，本库中的几个分词和词性标注函数调用jieba库。

### 对多行文本进行分词，返回字符串

```python
# 导入
from hufengguo import seg_str2str_by_jieba, segtag_str2str_by_jieba

# 准备文本
s = "\t\n\n  今天是个好日子，\t\n  \n心想的事儿\r都能成。\n \n\n"

# 分词
print("="*10)                                                           
print(seg_str2str_by_jieba(s))                                       
print("="*10)                                                           
print(seg_str2str_by_jieba(s, keep_empty_line=False))                
print("="*10)

print("\n"*2)

# 分词和词性标注
print("="*10)                                                           
print(segtag_str2str_by_jieba(s))                                       
print("="*10)                                                           
print(segtag_str2str_by_jieba(s, sepchar='|'))                          
print("="*10)                                                           
print(segtag_str2str_by_jieba(s, keep_empty_line=False))                
print("="*10)                                                           
print(segtag_str2str_by_jieba(s, sepchar='|', keep_empty_line=False))   
print("="*10)
```

### 调用jieba扩展库对一个文本文件进行分词和词性标注

```python
# 导入
from hufengguo import segtag_by_jieba

# 对单文件进行分词和词性标注操作
segtag_by_jieba(r"in.txt", r"out.txt")
```
本函数会自动判断文本文件的编码并进行读取，生成文件的默认编码是utf-8-sig。

### 调用jieba扩展库对一个目录下的文本文件进行分词和词性标注

```python
# 导入
from hufengguo import my_path2path, segtag_by_jieba

# 批量进行分词和词性标注操作
my_path2path(r"in", [".txt"], r"out", segtag_by_jieba)
```
本函数会自动搜索目录及子目录下的所有文本文件，进行分词和词性标注操作之后保存到目标目录，目标目录会保持跟源目录相同的目录结构。

本库提供的函数my_path2path()功能很强，它把目录对目录的多文件操作转化为单文件对单文件的操作。第二个参数可以换成其它的扩展名，第四个参数是一个函数名，我们可以换成其它的自定义函数来完成其它文本处理任务（要求自定义函数具有两个参数，第1个参数是源文件名，第2个参数是目标文件名，自定义函数的功能是对源文件进行自定义操作，操作结果写入目标文件）。



## 调用路径选择窗口类

### 独立调用

```python
# 导入
from hufengguo import my_path2path, segtag_by_jieba
from hufengguo import MyFilePathWindow

# 自定义函数
def segtag(fnin, fnout):
    print(f"正在处理 {fnin} ……")
    segtag_by_jieba(fnin, fnout)

# 赋值
pin, pout = MyFilePathWindow(
        "分词和词性标注路径选择",
        file1flag=False,
        file2flag=False,
    ).show()

# 调用
if pin is None or pout is None:
    print("用户取消了操作。")
else:
    my_path2path(pin, [".txt"], pout, segtag)
```

### 集成调用

```python
# 导入
from hufengguo import my_path2path, segtag_by_jieba, MyFilePathWindow
from tkinter import Button, Tk
from tkinter.messagebox import showinfo

# 自定义函数：对单个文本文件进行分词和词性标注
def segtag(fnin, fnout):
    # print(f"正在处理 {fnin} ……")
    segtag_by_jieba(fnin, fnout)

# 自定义函数，按钮响应函数
def do_segtag():
    fpin, fpout = MyFilePathWindow(
        "分词和词性标注路径选择",
        file1flag=False,
        file2flag=False,
        parent=main_app  # 指定父窗口
    ).show()
    
    if fpin and fpout:
        my_path2path(fpin, [".txt"], fpout, segtag)
        showinfo(title="信息反馈", message="操作完毕")
    else:
        showinfo(title="信息反馈", message="您取消了操作。")

# 界面
main_app = Tk()
main_app.title("主应用程序")
main_app.geometry("300x160")

Button(main_app, text="分词和词性标注", command=do_segtag).pack(pady=20)
Button(main_app, text="退出程序", command=main_app.destroy).pack()
main_app.mainloop()

```

## PDF操作



### 保护PDF

```python
from hufengguo import protect_pdf

fnin = r"test.pdf"
protect_pdf(fnin, r"test_默认保护.pdf")
protect_pdf(fnin, r"test_默认保护_用户密码12345.pdf", user_pwd="12345")
protect_pdf(fnin, r"test_默认保护_用户密码12345_所有者密码abcde.pdf",
            user_pwd="12345", owner_pwd="abcde")
protect_pdf(fnin, r"test_完全保护.pdf", -4096)
```

### 读取PDF的权限值

```python
from hufengguo import get_pdf_permissions

fn = r"test.pdf"
r = get_pdf_permissions(fn)    # 如有密码，加第二个参数
print(*r.items(), sep="\n")
```

### 解密PDF文件并取消保护
```python
from hufengguo import protect_pdf, get_pdf_permissions, decrypt_pdf

fnin, fntmp, fnout = r"test.pdf", r"tmp.pdf", r"test_out.pdf"
protect_pdf(fnin, fntmp, -4096, "12345")
decrypt_pdf(fntmp, fnout, "12345")
r = get_pdf_permissions(fnin)
print(*r.items(), sep="\n", end="\n\n")
r = get_pdf_permissions(fntmp, "12345")   # 如无密码，第二个参数省略
print(*r.items(), sep="\n", end="\n\n")
r = get_pdf_permissions(fnout, "12345")
print(*r.items(), sep="\n", end="\n\n")
```

### 分割PDF文件
```python
from hufengguo import split_pdf

fnin, fnout = r"test.pdf", r"test_out.pdf"
split_pdf(fnin, fnout, 10, 15, pwd="你的密码")  # 如PDF文件有打开有密码，必须加pwd参数
split_pdf(fnin, None, 10, 15)      # 如省略输出文件名，则会构造输出文件名：test_10_15.pdf
split_pdf(fnin, None, 10, None)    # 如省略结束页编号，则认为是从第10页到结束
split_pdf(fnin, None, None, 10)    # 如省略开始页编号，则认为是从第1页到第10页
```
