2025-09-10:仓库迁移

This commit is contained in:
2025-09-10 16:12:45 +08:00
parent e0e49b0ac9
commit 3130e336a1
146 changed files with 4066 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
# 众所周知split函数可以针对单个分隔符把字符串拆开
a = "suka,caonimade,shabi"
b = a.split(",")
print(b)
# 但是假如系统可以检测到这种粗鄙之语,那就会让🐎🐎消失
# 想要保卫自己的🐎,那就要粗鄙的隐晦一点:
a = "suka,*&&**caonimade,_&^shabi"
# 这时候关键词检测就暴毙了
b = a.split(",")
print(b)
# 但是聪明的审核会用re库来解决这个问题
import re
# re库中的split函数接受多个输入可以同时干掉多种干扰
b = re.split(r'[,*&^_]', a)
print(b)
# 如果要保留分隔符, 记得使用正则闭包
b = re.split(r'(,|&|^|_)', a)
print(b)

View File

@@ -0,0 +1,11 @@
import re
if __name__ == '__main__':
# 默认情况下re模块已经认识了某些unicode字符比如\d现在已经可以匹配unicode的数字
num = re.compile(r'\d+')
# match会从第一个字符开始匹配如果不匹配就返回None
print(num.match('123'))
print(num.match('\u0661\u0662\u0663'))
# 我的评价是别这样干在处理东西之前先将输入标准化为ascii编码是一个程序员的基本素养

View File

@@ -0,0 +1,24 @@
if __name__ == '__main__':
# 使用strip方法可以删除不要的字符串默认是删除空格
s = ' hello world \n'
print(s.strip())
# 同样的这个方法还有进阶版本lstrip和rstrip可以从左右开始检测指定符号进行删除
# 如果左边开头或右边开头没有指定符号,则不会起作用
s2 = '---hello world==='
print(s2.lstrip('-'))
print(s2.rstrip('='))
print(s2.strip('-='))
# 在这个例子中hello world中间的空格不会被strip系列函数删除因为这个方法不会管字符串中间的字符
# 如果需要删除hello world中间的空格请使用replace方法
# 在一个文件中,我们可以这样进行每一行的信息过滤:
# with open(file) as f:
# lines = (line.strip() for line in f)
# for line in lines:
# print(line)

View File

@@ -0,0 +1,26 @@
import sys
import unicodedata
if __name__ == '__main__':
# 总有脑瘫喜欢输入一些奇奇怪怪的东西,这个时候我们就需要做一些过滤操作
s = 'pyth\u0303on\fis\tawesome\r\n'
# 这个字符串看起来就非常恶心了这时候我们可以用translate方法对一些特殊符号进行迭代
remap = {
ord('\t'): ' ',
ord('\f'): ' ',
ord('\r'): None,
}
s = s.translate(remap)
print(s)
# 这个时候我们就过滤掉了各种空格符和回车符
# 我们也可以构建更大的order_dict去把unicode过滤掉
b = unicodedata.normalize("NFD", s)
# 对每一个unicode建立一个None的映射
cmb_dict = dict.fromkeys(c for c in range(sys.maxunicode) if unicodedata.combining(chr(c)))
b = b.translate(cmb_dict)
print(b)
# 如果只是简单的替换操作那么replace函数已经很好了速度也很快
# 在做字符映射操作的时候可以使用translate方法并构建一个映射字典

View File

@@ -0,0 +1,22 @@
if __name__ == "__main__":
text = 'Hello World'
# 如果想要对齐字符串可以使用ljest、rjust和center方法
print(text.ljust(20))
print(text.rjust(20))
print(text.center(20))
# 当然,这个轮椅也支持填充操作
print(text.ljust(20, '='))
print(text.rjust(20, '-'))
print(text.center(20, '='))
# 除了轮椅函数建议使用format函数这个东西更加泛用还能进行格式转换
print(format(text, '-<20')) # <表示宽度20居左
print(format(text, '=>20')) # >表示宽度20居右
print(format(text, '+^20')) # ^表示宽度20居中
# <>^前面的符号表示使用该符号填充
# format的好处主要在于它的处理对象不仅是字符串可以对任何数据形式进行格式化
num = 1.23456
print(format(num, '=^20.2f')) # 这表示宽度20保留两位小数居中使用=填充

View File

@@ -0,0 +1,15 @@
if __name__ == "__main__":
# 如果有一堆字符串, 那我想join函数是一个好选择, 但如果就几个那用+就可以了
parts = ["Is", "Chicago", "Not", "Chicago?"]
str_c = ' '.join(parts)
print(str_c)
# 如果我有密钥的两部分想把a和b连接在一起那可以这样
keyword = 'su' 'ka'
print(keyword)
# 在实际运用中,如果遇到一堆字符串拼接,千万别用+=,这样会产生大量内存垃圾
# 如果有大量的片段需要拼接,则应该考虑使用生成器函数(字段确定的情况下)

View File

@@ -0,0 +1,43 @@
import sys
if __name__ == "__main__":
# 一般来说,我们用{}和format函数对字符串进行插值
s = "{name} has {n} messages"
s1 = s.format(name="Sam", n=10)
print(s1)
# 当然如果你想偷懒,也可以这样:
name = "Sam"
n = 10
s2 = s.format_map(vars())
print(s2)
# 在上面这段代码中vars函数会从堆栈里自动寻找变量名称的值
# vars还能解析类实例
class INFO:
def __init__(self, name, n):
self.name = name
self.n = n
info = INFO(name, n)
s3 = s.format_map(vars(info))
print(s3)
# 爽吗?确实爽,但是有一个缺点,在填充值缺失的时候这玩意儿会报错
try:
s4 = s.format(name=name)
except KeyError:
print("少参数")
# 我们可以定义一个类的__missing__方法来防止出现这种情况
class Safe_Sub(dict):
def __missing__(self, key):
return '{'+ key +'}'
del n
print(s.format_map(Safe_Sub(vars())))
# 如果经常操作,那么可以把这个功能藏在函数里,同时从当前调用的堆栈里找到变量(我反正不建议这么干,不过得知道)
def sub(text):
# 不代码里tmd堆栈这是手贱行为可能导致各种bug除非有必要的理由否则不要这么做
return text.format_map(Safe_Sub(sys._getframe(1).f_locals))
name = "Suka"
print(sub(s))

View File

@@ -0,0 +1,20 @@
import textwrap
import os
if __name__ == '__main__':
words = ' '.join(["look", "into", "my", "eyes", "look", "into", "my", "eyes",
"the", "eyes", "the", "eyes", "the", "eyes", "not", "around", "the",
"eyes", "don't", "look", "around", "the", "eyes", "look", "into",
"my", "eyes", "you're", "under"])
print(words)
# 可以看到这样打印出来的字符串巨长无比如果想要控制行宽度就用textwrap模块
print(textwrap.fill(words, 70))
print(textwrap.fill(words, 40))
# 第二个参数width可以控制显示宽度如果是控制台输出你还能去找os.get_terminal_size()
# 注意由于未知原因这在pycharm中不好使2024.8.27
t_width = os.get_terminal_size().columns
print(t_width)
print(textwrap.fill(words, t_width))
# 用的应该不多在需要显示长字符串的时候去查textwrap库就行

View File

@@ -0,0 +1,4 @@
# 这本书的年代有些久远当时HTML和XML解析器还不是特别完善
# 在现在的工具中想要处理HTML和XML文件只需要寻找HTML Parser和XML解析库就行

View File

@@ -0,0 +1,37 @@
import re
from collections import namedtuple
if __name__ == "__main__":
text = 'foo = 23 + 42 * 10'
# 我们想要将这个字符串解析成这个样子:
# tokens = [('NAME', 'foo'), ('EQ', '='), ('NUMS', '23'), ('PLUS', '+'),
# ('NUMS', '42'), ('TIMES', '*'), ('NUMS', '10')]
# 首先,我们要对每种情况编写一个捕获组
NAME = r'(?P<NAME>[a-zA-Z_][a-zA-Z_0-9]*)'
NUM = r'(?P<NUM>\d+)'
PLUS = r'(?P<PLUS>\+)'
TIMES = r'(?P<TIMES>\*)'
EQ = r'(?P<EQ>=)'
WS = r'(?P<WS>\s+)'
# 把这些捕获组静态编译给re模块
master_pat = re.compile('|'.join([NAME,NUM,PLUS,TIMES,EQ,WS]))
# 定义一个数据结构来存储每个部分
Token = namedtuple('Token', ['type', 'value'])
def generate_tokens(pat, text):
# 调用re.compile的scanner模块来扫描并用iter模块将其变成可迭代对象进行迭代
scanner = pat.scanner(text)
for m in iter(scanner.match, None):
# 生成结构来存储分词
yield Token(m.lastgroup, m.group())
# 对分词类型进行过滤,去掉空格
tokens = (tok for tok in generate_tokens(master_pat, text) if tok.type != 'WS')
for tok in tokens:
print(tok)
# 看起来很简单是吧唯一的难点就在compile的时候
# 要把大词放前面先搜完再搜小词,保证较长的模式先匹配;比如<=的顺序就应该比<靠前

View File

@@ -0,0 +1,3 @@
"""
我的评价是去看编译原理的文本解析部分
"""

View File

@@ -0,0 +1,21 @@
from numpy.core.defchararray import startswith
if __name__ == '__main__':
str = "https://www.baidu.com"
str2 = "http://www.baidu.cn"
str3 = "suka"
# 如果想要在字符串首进行匹配,可以使用:
is_start_with_https = str.startswith("https")
print(is_start_with_https)
# 这会输出一个布尔值,
## 比如上面匹配成功就会输出True
# 同理可以设置endswith
is_end_with_dotcom = str.endswith(".com")
print(is_end_with_dotcom)
# 如果想要匹配多种开头和结尾,可以将函数输入改成元组()
is_url = [url for url in [str, str2, str3] if url.startswith(('http', 'https'))]
print(is_url)
# 当然,复杂的操作还请使用正则表达式进行匹配,不过简单的检查用这个方法那是又快又好

View File

@@ -0,0 +1,33 @@
import re
from pyasn1.codec.ber.decoder import decode
if __name__ == '__main__':
data = b'Hello World'
# 目前字节串已经支持大部分和字符串相同的操作
data05 = data[0:5]
print(data05)
is_startwith_hello = data.startswith(b'Hello')
print(is_startwith_hello)
data_sp = data.split()
print(data_sp)
data_suka = data.replace(b'Hello', b'Hello Suka')
print(data_suka)
# 唯一需要注意的是如果用re做了匹配那记得要用字节串的形式来匹配
data = b'foo:bar,spam'
try:
re.split('[:,]', data)
except:
print("匹配错误,换字节串匹配")
data_bsp = re.split(b'[:,]', data)
print(data_bsp)
# 字节串上的字符不能直接被识别需要先用ascii解码
print(data[0])
print(data.decode("ascii")[0])
# 我的建议是除非万不得已请不要用字节串处理文本统一使用ascii解码成字符串后再进行操作

View File

@@ -0,0 +1,26 @@
from fnmatch import fnmatch, fnmatchcase
if __name__ == '__main__':
# 如果想用shell通配符做字符串匹配可以用上面的这两个函数
is_txt = fnmatch("suka.txt", "*.txt")
print(is_txt)
is_txt = fnmatchcase("suka.txt", "??ka.txt")
print(is_txt)
# 注意fnmatchcase不会对输入的name进行大小写标准化而fnmatch会对输入标准化后再进行匹配
# 需要小心的是大小写标准化的模式与底层文件系统相同比如windows不需要区分大小写但是mac要
address = [
'5412 N CLARK ST',
'1060 W ADDISON ST',
'1039 W GRANVILLE AVE',
'2122 N CLARK ST',
'4802 N BROADWAY'
]
# 可以用正则进行筛选
ST = [addr for addr in address if fnmatchcase(addr, "* ST")]
print(ST)
NUM_S = [addr for addr in address if fnmatchcase(addr, '54[0-9][0-9] *CLARK*')]
print(NUM_S)

View File

@@ -0,0 +1,49 @@
import re
if __name__ == '__main__':
# 如果只是简单的文字匹配或者查找,下面三个方法足以解决问题:
url = "http://www.baidu.com"
url.startswith("http")
url.endswith(".com")
url.find("baidu")
# 但如果是更加复杂的匹配就要用到re库的正则了
text1 = '11/27/2012'
text2 = 'Nov 27, 2012'
if re.match(r'\d+/\d+/\d+', text1):
print("yes")
else:
print("no")
if re.match(r'\d+/\d+/\d+', text2):
print("yes")
else:
print("no")
# match可以被一次性消费但是如果想要多次匹配就要先把正则编译
datepat = re.compile(r'\d+/\d+/\d+')
if datepat.match(text1):
print("yes")
else:
print("no")
if datepat.match(text2):
print("yes")
else:
print("no")
# 这里要注意的是match方法是从头匹配如果要匹配的内容在一堆垃圾里面请使用findall
# 我们还会使用捕获组,这样可以把每个组单独提取出来
datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
m = datepat.match(text1)
print(m.group(0))
print(m.group(1))
print(m.group(2))
print(m.group(3))
# match只能匹配开头它不管结尾如果想要精确匹配需要加休止符$
datepat = re.compile(r'(\d+)/(\d+)/(\d+)$')

View File

@@ -0,0 +1,22 @@
import re
if __name__ == "__main__":
text = "yeah, but no, but yeah, but no, but yeah"
# 简单的替换可以使用replace函数来完成
text_change = text.replace('yeah', 'yep')
print(text_change)
# 对复杂的替换我们可以使用re.sub模块
text = "Today is 11/27/2012. PyCon starts 3/12/2013"
text_change = re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text)
print(text_change)
# 如果需要多次替换记得先编译再sub
datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
print(datepat.sub(r'\3-\1-\2', text))
# 想要知道完成了几次替换可以使用subn
# subn返回一个元组结构为替换后的字符串 替换次数)
print(datepat.subn(r'\3-\1-\2', text))

View File

@@ -0,0 +1,35 @@
import re
if __name__ == '__main__':
text = "UPPER PYTHON, lower python, mixed Python"
# 想要找到所有的python可以在函数里面找一下有没有flag关键字并设为re.IGNORECASE
pythons = re.findall('python', text, flags=re.IGNORECASE)
print(pythons)
# 但是这样在替换的时候就有问题发生,不能把替换文本的大小写设置成和原文本一样
python_replace = re.sub('python', 'snake', text, flags=re.IGNORECASE)
print(python_replace)
# 这个时候我们需要一个辅助函数
def matchcase(word):
def replace(m):
text = m.group()
if text.isupper():
return word.upper()
elif text.islower():
return word.lower()
elif text[0].isupper():
# 这个函数将字符串的首字母大写,其余部分转成小写
return word.capitalize()
else:
return word
return replace
python_replace_with_func = re.sub('python', matchcase('snake'), text, flags=re.IGNORECASE)
print(python_replace_with_func)
# 这个辅助函数结构陌生,这里记个笔记备注一下防止以后再看忘记:
# 1.首先sub函数检测到要调用matchcase函数进入函数体返回replace函数 sub->matchcsae
# 2.此时matchcase函数的输入word仍在堆栈中等待调用 matchcase -replace-> sub
# 3.在替换的时候sub函数将识别到的python替换成replace(被识别到的部分) text -> (a1,a2,a3,...)
# 4.replace函数返回大小写处理结果 replace(a1), replace(a2), ...
# 5.函数返回被替换字符串re.sub函数进行替换 将识别到的关键词替换成处理过的word

View File

@@ -0,0 +1,18 @@
import re
if __name__ == '__main__':
# 在进行文本匹配的时候re库使用的是贪心算法即找最长匹配字符串
text1 = 'Computer says "no".'
text2 = 'Computer says "yes" and "no".'
# 这样的算法在简单的环境中不会出现问题,但如果遇到闭包匹配(最典型的是双引号)就会出现问题
said = re.compile(r'\"(.*)\"')
print(said.findall(text1))
# 看,这里就输出了距离最长的两个引号中间的内容
print(said.findall(text2))
# 问题就出现在.匹配字符上,默认.*会匹配除了\n以外的所有字符其中也包括“”
# 解决方案是强制取消正则的贪心算法,进行最短匹配
# 技术上我们在.*后界面加一个?来强制取消贪心
said_shot = re.compile(r'\"(.*?)\"')
print(said_shot.findall(text2))

View File

@@ -0,0 +1,20 @@
import re
if __name__ == '__main__':
# 正常情况下,我们会想用.来匹配所有字符串,但这个东西不能匹配换行符
text1 = '/*This is a comment*/'
text2 = '''/*This is a
multiline comment */'''
comment = re.compile(r'/\*(.*?)\*/')
print(comment.findall(text1))
print(comment.findall(text2))
# 你会发现欸我靠咋匹配不到了,那是因为由于没办法识别\n,第二行被抛弃了
# 想要识别出\n,需要使用(?:.|\n)指定一个非捕获组,意思是在识别到/n的时候只做匹配但不触发捕获退出
comment_pro = re.compile(r'\*((?:.|\n)*?)\*/')
print(comment_pro.findall(text2))
# 对于这种简单的情况可以在compile函数中加入一个参数re.DOTALL来让.匹配包括\n在内的所有字符串
# PS复杂情况请另请高明
comment_pro_se = re.compile(r'\*(.*?)\*/', re.DOTALL)
print(comment_pro_se.findall(text2))

View File

@@ -0,0 +1,37 @@
import unicodedata
if __name__ == '__main__':
s1 = 'Spicy Jalape\u00f1o'
s2 = 'Spicy Jalapen\u0303o'
# 可以看到某些字符串的表示在unicode下有多种选项
print(s1,s2)
print(s1==s2)
# 显然这种情况在我们判断字符串的时候极其不利这时候我们就需要把unicode编码进行规范
# 有两种规范方式NFC全组成和NFD组合字符
t1 = unicodedata.normalize('NFD', s1)
t2 = unicodedata.normalize('NFD', s2)
print(t1, t2)
print(t1==t2)
print(ascii(t1))
t3 = unicodedata.normalize('NFC', s1)
t4 = unicodedata.normalize('NFC', s2)
print(ascii(t3))
# unicodedata同时还提供NFKC和NFKD编码这种编码提供了额外的兼容功能能把下面这种字符分开
s = '\ufb01'
print(s)
print(unicodedata.normalize('NFD', s))
print(unicodedata.normalize('NFKC', s))
print(unicodedata.normalize('NFKD', s))
# 如果要去除音符标记~那么我们可以先用组合字符NFD标准化再进行去除
suka = unicodedata.normalize('NFD', s1)
print(suka)
suka = ''.join(c for c in unicodedata.normalize('NFD', suka) if not unicodedata.combining(c))
print(suka)
# 在上面的例子里,我们使用了unicodedata.combining()函数来判断字符是否属于组合型字符