Po学校Python第四课(循环+文件操作+字典+函数)

本文详细介绍了Python中文件的打开、读取、写入等基本操作,并演示了如何使用pickle模块处理复杂数据类型。此外,深入探讨了字典的各种操作及应用场景,包括模拟列表、稀疏数据结构等。

登陆系统

登陆三次


count =0

while count <3:

count+=1

name=inpu("请输入用户名")

if name="root":

password=input("请输入密码")

if password=="root":

print("登陆成功")

break

else:

print("密码错误")

else:

print("用户名错误")



作业:提示已经输入了三次


count=0

while count<3:

count+=1

name=input("请输入用户名")

if name=="root":

password=input("请输入密码")

if password=="root":

print("登陆成功")

break

else:

print("密码错误")

else:

print("用户名错误")

else:

print("已经输入错误三次")



FILE文件


f=open("demo.txt")

f.readline()

123

f.readline()

456

readline()这句是逐行读取,一次读一行

f.readlines()

123 456

readlines()这句是一下全部读取出来

close()是关闭


s=f.readline()

则s.      这个点之后也会有很多的方法。比对啥的


fp = open("test.txt",w)     直接打开一个文件,如果文件不存在则创建文件

关于open 模式:

w     以写方式打开,
a     以追加模式打开 (从 EOF 开始, 必要时创建新文件)
r+     以读写模式打开
w+     以读写模式打开 (参见 w )
a+     以读写模式打开 (参见 a )
rb     以二进制读模式打开
wb     以二进制写模式打开 (参见 w )
ab     以二进制追加模式打开 (参见 a )
rb+    以二进制读写模式打开 (参见 r+ )
wb+    以二进制读写模式打开 (参见 w+ )
ab+    以二进制读写模式打开 (参见 a+ )

fp.read([size])                     #size为读取的长度,以byte为单位

fp.readline([size])                 #读一行,如果定义了size,有可能返回的只是一行的一部分

fp.readlines([size])                #把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长,也就是说可能只读到文件的一部分。

fp.write(str)                      #把str写到文件中,write()并不会在str后加上一个换行符

fp.writelines(seq)            #把seq的内容全部写到文件中(多行一次性写入)。这个函数也只是忠实地写入,不会在每行后面加上任何东西。

fp.close()                        #关闭文件。python会在一个文件不用后自动关闭文件,不过这一功能没有保证,最好还是养成自己关闭的习惯。  如果一个文件在关闭后还对其进行操作会产生ValueError

fp.flush()                                      #把缓冲区的内容写入硬盘

fp.fileno()                                      #返回一个长整型的”文件标签“

fp.isatty()                                      #文件是否是一个终端设备文件(unix系统中的)

fp.tell()                                         #返回文件操作标记的当前位置,以文件的开头为原点

fp.next()                                       #返回下一行,并将文件操作标记位移到下一行。把一个file用于for … in file这样的语句时,就是调用next()函数来实现遍历的。

fp.seek(offset[,whence])              #将文件打操作标记移到offset的位置。这个offset一般是相对于文件的开头来计算的,一般为正数。但如果提供了whence参数就不一定了,whence可以为0表示从头开始计算,1表示以当前位置为原点计算。2表示以文件末尾为原点进行计算。需要注意,如果文件以a或a+的模式打开,每次进行写操作时,文件操作标记会自动返回到文件末尾。

fp.truncate([size])                       #把文件裁成规定的大小,默认的是裁到当前文件操作标记的位置。如果size比文件的大小还要大,依据系统的不同可能是不改变文件,也可能是用0把文件补到相应的大小,也可能是以一些随机的内容加上去。


最基本的文件操作当然就是在文件中读写数据。这也是很容易掌握的。现在打开一个文件以进行写操作: 

1. fileHandle = open ( 'test.txt', 'w' )  

fileHandle = open ( 'test.txt', 'w' ) 

‘w'是指文件将被写入数据,语句的其它部分很好理解。下一步就是将数据写入文件: 

1. fileHandle.write ( 'This is a test.\nReally, it is.' )  

fileHandle.write ( 'This is a test.\nReally, it is.' ) 

这个语句将“This is a test.”写入文件的第一行,“Really, it is.”写入文件的第二行。最后,我们需要做清理工作,并且关闭文件: 

1. fileHandle.close()  

fileHandle.close() 

正如你所见,在Python的面向对象机制下,这确实非常简单。需要注意的是,当你再次使用“w”方式在文件中写数据,所有原来的内容都会被删除。如果想保留原来的内容,可以使用“a”方式在文件中结尾附加数据: 

1. fileHandle = open ( 'test.txt', 'a' )  
2. fileHandle.write ( '\n\nBottom line.' )  
3. fileHandle.close()  

fileHandle = open ( 'test.txt', 'a' ) 
fileHandle.write ( '\n\nBottom line.' ) 
fileHandle.close() 

然后,我们读取test.txt,并将内容显示出来: 

1. fileHandle = open ( 'test.txt' )  
2. print fileHandle.read()  
3. fileHandle.close()  

fileHandle = open ( 'test.txt' ) 
print fileHandle.read() 
fileHandle.close() 

以上语句将读取整个文件并显示其中的数据。我们也可以读取文件中的一行: 

1. fileHandle = open ( 'test.txt' )  
2. print fileHandle.readline() # "This is a test."  
3. fileHandle.close()  

fileHandle = open ( 'test.txt' ) 
print fileHandle.readline() # "This is a test." 
fileHandle.close() 


同时,也可以将文件内容保存到一个list中: 

1. fileHandle = open ( 'test.txt' )  
2. fileList = fileHandle.readlines()<div></div>  
3. for fileLine in fileList:  
4.     print '>>', fileLine  
5. fileHandle.close()  

fileHandle = open ( 'test.txt' ) 
fileList = fileHandle.readlines() 
for fileLine in fileList: 
print '>>', fileLine 
fileHandle.close() 

Python在读取一个文件时,会记住其在文件中的位置,如下所示: 

1. fileHandle = open ( 'test.txt' )  
2. garbage = fileHandle.readline()  
3. fileHandle.readline() # "Really, it is."fileHandle.close()  

fileHandle = open ( 'test.txt' ) 
garbage = fileHandle.readline() 
fileHandle.readline() # "Really, it is."fileHandle.close() 

可以看到,只有第二行显示出来。然而,我们可以让Python从头开始读来解决这个问题: 

1. fileHandle = open ( 'test.txt' )  
2. garbage = fileHandle.readline()  
3. fileHandle.seek ( 0 )  
4. print fileHandle.readline() # "This is a test."  
5. fileHandle.close()  

fileHandle = open ( 'test.txt' ) 
garbage = fileHandle.readline() 
fileHandle.seek ( 0 ) 
print fileHandle.readline() # "This is a test." 
fileHandle.close() 

在上面这个例子中,我们让Python从文件第一个字节开始读取数据。所以,第一行文字显示了出来。当然,我们也可以获取Python在文件中的位置: 

1. fileHandle = open ( 'test.txt' )  
2. print fileHandle.readline() # "This is a test."  
3. print fileHandle.tell() # "17"  
4. print fileHandle.readline() # "Really, it is."  

fileHandle = open ( 'test.txt' ) 
print fileHandle.readline() # "This is a test." 
print fileHandle.tell() # "17" 
print fileHandle.readline() # "Really, it is." 

或者在文件中一次读取几个字节的内容: 

1. fileHandle = open ( 'test.txt' )  
2. print fileHandle.read ( 1 ) # "T"  
3. fileHandle.seek ( 4 )  
4. print FileHandle.read ( 1 ) # " "(原文有错)  

fileHandle = open ( 'test.txt' ) 
print fileHandle.read ( 1 ) # "T" 
fileHandle.seek ( 4 ) 
print FileHandle.read ( 1 ) # " "(原文有错) 

在Windows和Macintosh环境下,有时可能需要以二进制方式读写文件,比如图片和可执行文件。此时,只要在打开文件的方式参数中增加一个“b”即可: 

1. fileHandle = open ( 'testBinary.txt', 'wb' )  
2. fileHandle.write ( 'There is no spoon.' )  
3. fileHandle.close()  

fileHandle = open ( 'testBinary.txt', 'wb' ) 
fileHandle.write ( 'There is no spoon.' ) 
fileHandle.close() 

1. fileHandle = open ( 'testBinary.txt', 'rb' )  
2. print fileHandle.read()  
3. fileHandle.close()  

fileHandle = open ( 'testBinary.txt', 'rb' ) 
print fileHandle.read() 
fileHandle.close() 



前一节中介绍的模块,可以实现在文件中对字符串的读写。 
然而,有的时候,你可能需要传递其它类型的数据,如list、tuple、dictionary和其它对象。在Python中,你可以使用Pickling来完成。你可以使用Python标准库中的“pickle”模块完成数据编组。 
下面,我们来编组一个包含字符串和数字的list: 

1. import pickle  
2.   
3. fileHandle = open ( 'pickleFile.txt', 'w' )  
4. testList = [ 'This', 2, 'is', 1, 'a', 0, 'test.' ]  
5. pickle.dump ( testList, fileHandle )  
6. fileHandle.close()  

import pickle 

fileHandle = open ( 'pickleFile.txt', 'w' ) 
testList = [ 'This', 2, 'is', 1, 'a', 0, 'test.' ] 
pickle.dump ( testList, fileHandle ) 
fileHandle.close() 

拆分编组同样不难: 

1. import pickle  
2.   
3. fileHandle = open ( 'pickleFile.txt' )  
4. testList = pickle.load ( fileHandle )  
5. fileHandle.close()  

import pickle 

fileHandle = open ( 'pickleFile.txt' ) 
testList = pickle.load ( fileHandle ) 
fileHandle.close() 

现在试试存储更加复杂的数据: 

1. import pickle  
2.   
3. fileHandle = open ( 'pickleFile.txt', 'w' )  
4. testList = [ 123, { 'Calories' : 190 }, 'Mr. Anderson', [ 1, 2, 7 ] ]  
5. pickle.dump ( testList, fileHandle )  
6. fileHandle.close()  

import pickle 

fileHandle = open ( 'pickleFile.txt', 'w' ) 
testList = [ 123, { 'Calories' : 190 }, 'Mr. Anderson', [ 1, 2, 7 ] ] 
pickle.dump ( testList, fileHandle ) 
fileHandle.close() 

1. import pickle  
2.   
3. fileHandle = open ( 'pickleFile.txt' )  
4. testList = pickle.load ( fileHandle )  
5. fileHandle.close()  

import pickle 

fileHandle = open ( 'pickleFile.txt' ) 
testList = pickle.load ( fileHandle ) 
fileHandle.close() 






dict字典

>>>mydict={'key1':'value1','key2':123123}

>>>mydict['key1']

value1

>>>mydice['key2']#列出key2的内容

123123

>>>mydice['key3']=456     #往字典里加内容

>>>mydict

{'key1':'value1','key2':123123,'key3':456}

>>>mydict[123123]=111111#修改内容

{'key1':'value1','key2':111111,'key3':456}





2、常见的字典操作
可以查看库手册或者运行dir(dict)或者help(dict),类型名为dict。当写成常量表达式时,字典以一系列"键:值(key:value)”对形式写出的,用逗号隔开,用大括号括起来。可以和列表和元组嵌套
操作                        解释
D1={}                        空字典
D={'one':1}                    增加数据
D1[key]='class'                    增加数据:已经存在就是修改,没有存在就是增加数据
D2={'name':'diege','age':18}            两项目字典
D3={'name':{'first':'diege','last':'wang'},'age':18} 嵌套
D2['name']                    以键进行索引计算
D3['name']['last']                字典嵌套字典的键索引
D['three'][0]                    字典嵌套列表的键索引
D['six'][1]                    字典嵌套元组的键索引
D2.has_key('name')                 方法:判断字典是否有name键
D2.keys()                    方法:键列表
list(D)                        获取D这个字典的的KEY的 MS按字典顺序排序成一个列表
D2.values()                      方法:值列表
'name' in D2                    方法:成员测试:注意使用key来测试
D2.copy()                     方法:拷贝
D2.get(key,deault)                方法:默认 如果key存在就返回key的value,如果不存在就设置key的value为default。但是没有改变原对象的数据
D2.update(D1)                    方法:合并。D1合并到D2,D1没有变化,D2变化。注意和字符串,列表好的合并操作”+“不同
D2.pop('age')                    方法:删除 根据key删除,并返回删除的value
len(D2)                        方法:求长(存储元素的数目)
D1[key]='class'                    方法:增加:已经存在的数据就是修改,没有存在就是增加数据
D4=dict(name='diege',age=18)            其他构造技术
D5=dict.fromkeys(['a','b'])                 其他构造技术 dict.fromkeys 可以从一个列表读取字典的key 值默认为空,可指定初始值.两个参数一个是KEY列表,一个初始值
>>> D4
{'a': None, 'b': None}
>>> D5=dict.fromkeys(['a','b','c'],0)
>>> D5
{'a': 0, 'c': 0, 'b': 0}
D6=dict(zip(keyslist.valslist))             ???
>>> D={}     
>>> D={'one':1}
>>> D
{'one': 1}
列表不能通过这样的方法来增加数据,列表只能通过append方法,列表之能通过L[1]='A'这样的方法来修改已存在序列的数据。
二、实际应用中的字典
1、字典的基本操作
1)、创建字典的方法 和修改
全部数据一起添加
>>> D={'name':'diege','age':18}
>>> D
{'age': 18, 'name': 'diege'}

>>> D={}
>>> D['name']='diege'
>>> D['age']=18         
>>> D
{'age': 18, 'name': 'diege'}
>>> D1['age']=19
>>> D1
{'age': 19, 'name': 'diege'}
同样键不存在是新添加数据,键存在就是修改数据

>>> D1=dict(name='diege',age=18)
>>> D1
{'age': 18, 'name': 'diege'}
将数据按按key=value作为参数传递给dict()
dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs
>>> D=dict.fromkeys(['name','age'])  
>>> D
{'age': None, 'name': None}
创建只有key没有value的字典。

>>> D=dict.fromkeys(['name','age'],0)  
>>> D
{'age': 0, 'name': 0}
2)、索引
>>> D['age']
18
3)、取长
>>> len(D)
2
4)、键存在判断-参数使用key
>>> D.has_key('name')
True
5)、成员判断 使用key
>>> 'age' in D
True
6)、字典的键查看 返回键的列表
>>> D.keys()         
['age', 'name']
7)、字典的值查看 返回值的列表
>>> D.values()
[18, 'diege']
8)、拷贝
D2.copy()     
2、原处修改字典
1)增加数据
>>> D['age']=18         
>>> D
{'age': 18, 'name': 'diege'}
>>> D1['age']=19
>>> D1
{'age': 19, 'name': 'diege'}
同样键不存在是新添加数据,键存在就是修改数据

2)删除数据
根据键删除
pop方法是从字典中删除一个键并返回它的值  
>>> D.pop('age')  
18
方法是从字典中删除一个键并返回它的值  
>>> del D['age']
18
从字典前面一对K:V的方式删除,并返回K,V合成的元组
>>> D3.popitem() 
('age', 18)
清空字典所有数据
D1.clear()
3)合并数据
D2.update(D1)                    方法:合并。D1合并到D2,D1没有变化,D2变化。注意和字符串,列表好的合并操作”+“不同
>>> D1
{'name': 'diege'}
>>> D2
{'class': 2, 'level': 2012}
>>> D2.update(D1)
>>> D1
{'name': 'diege'}
>>> D2
{'class': 2, 'name': 'diege', 'level': 2012}

3、其他字典方法
字典方法提供很多工具,例如 字典keys,valuse和items方法分别返回字典的键列表,值列表和(key,value)对元组
key列表
>>> D2.keys()
['class', 'name', 'level']
value列表
>>> D2.values()    
[2, 'diege', 2012]
K,V元组的列表
>>> D2.items()      
[('class', 2), ('name', 'diege'), ('level', 2012)]
>>> D2.viewkeys()       
dict_keys(['class', 'name', 'level'])
>>> D2.viewvalues()    
dict_values([2, 'diege', 2012])
>>> D2.viewitems()      
dict_items([('class', 2), ('name', 'diege'), ('level', 2012)])

4、语言表
>>> table={'Python':'Guido',
... 'Perl':'Larry',
... 'Tcl':'John'}

for lang in table.keys():
...  print lang,'\t',table[lang]
... 
Python  Guido
Tcl     John
Perl    Larry
因为字典并非序列,无法像字符串和列表那样直接通过一个for语句迭代他们。但如果要遍历字典的键列表很容易。调用字典的keys()方法,返回经过排序之后所有键的列表。再用for循环进行迭代。
实际上,Python也能然给你遍历字典的键的列表,而并不用在多数for循环中调用keys方法.就任何字典D而言,写成for key in D:和写成完整的for key in D.keys():效果是一样的
>>> for key in table:
...  print key
... 
Python
Tcl
Perl
>>> for key in table.keys():
...  print key
... 
Python
Tcl
Perl
>>> for key in table.values():
...  print key                
... 
Guido
John
Larry
三、字典用法注意事项
*序列运算无效。无法有序合并和分片
*对新索引赋值会增加项。
*键不一定总是字符串。任何不可变对象都可以(也就是不是列表)
1、使用字典模拟灵活的列表
当使用列表的时,对在列表末尾外的偏移赋值是非法的。
>>> L=[]
>>> L[99]='diege'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
虽然可以使用重复预先分配足够的大的列表(例如 [0]*100)。但也可以使用字典来坐类似的事。这样就不需要这样的空间分配了。
使用整数键时,字典可以效仿列表再偏移赋值时增长
>>> [0]*100>>> L=[0]*100      
>>> L[99]='diege
>>> D={}
>>> D[99]='diege'
>>> D[99]
'diege
这样的不用将来可能会用到的会被赋值的所有位置都分配空间。这样字典很像更具灵活性的列表。
2、字典用于稀疏数据结构
例如多维数组中只有少数位置上有存储的值
>>> M={}
>>> M[(2,3,4)]=88
>>> M[(7,8,9)]=99   
>>> X=2;Y=3;Z=4 
>>> M[(X,Y,Z)]
88
>>> M
{(2, 3, 4): 88, (7, 8, 9): 99}
这个数组中只有两个位置(2,3,4),(7,8,9)有值,其他位置都未空。键是元组,他们记录非空元素的坐标。我们并不是分配一个庞大而几乎为空的三维矩阵,而是使用一个简单的两个元素的字典。通过这一方式读取空元素的时,会触发键不存在的异常。因为这些元素实质上并没有被存储。
>>> M[(5,6,7)]     
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: (5, 6, 7)
3、避免missing-key错误
读取不存在的键的错误在稀疏矩阵中很常见。然而可能并不希望程序因为这一次错误而被关闭。这里有三种方式可以让我们填入默认值而不会出现这样
的错误提示,
1、)使用if语句预先对键进行测试。
>>> if M.has_key((5,6,7)): 
...  print M[(5,6,7)]
... else:
...  print 0
... 
0
2)、使用try语句明确地捕获并修复这一异常。
>>> try:
...  print M[(5,6,7)]
... except KeyError:
...  print 0
... 
0
3)、使用get方法为不存在的键提供一个默认值
>>> M.get((2,3,4),0)   
88
>>> M.get((5,6,7),0)
0
从编程的需要方面来说,get方法是三者中最简捷的。
4、使用字典作为“记录”
一般说来,字典可以取代搜索数据结构(因为用键进行索引是一种搜索操作),并且可以表示多种结构化信息的类型。例如,字典是在程序范围中多种描述某一项
属性的方法之一。也就是说,它们能偶扮演其他语言中的“记录”和结构相同的角色。随时间通过向新键赋值来填写字典的列子
>>> rec={}
>>> rec['name']='diege'
>>> rec['age']=28         
>>> rec['job']='sa/db'
>>> print rec['name']
diege
特别是在嵌套的时候,Python的内建数据类型可以很轻松地表达结构化信息。使用字典来捕获对象的属性,但是它是一次性写好的,而且嵌套了一个列表和一个字典来表达结构化属性的值。
>>> offer={'name':'diege','jobs':['sa','dba'],'web':'www.skylog.cn/~diege','home':{'state':'SH','zip':8088}}
当去读嵌套对象的元素时,只要简单地吧索引操作串起来就可以了
>>> offer['name']
'diege'
>>> offer['jobs'][1] 
'dba'
>>> offer['home']['state']
'SH
5、创建字典的其他方法
1)
>>> {'name':'diege','age':45}
{'age': 45, 'name': 'diege'}
2)
>>> D={}
>>> D['name']='lily'
>>> D['age']=18        
>>> D
{'age': 18, 'name': 'lily'}
3)
>>> dict(name='kelly',age=19)    
{'age': 19, 'name': 'kelly'}
注意这里name,age没有 ’‘括起来,因为这里是变量。
4)
>>> dict([('name','tom'),('age',23)])
{'age': 23, 'name': 'tom'}
这里将每一个数据(属性),做为元组放到一个列表里传递给dict函数

4种方法的选择技巧
*如果可以事先拼除整个字典,那么第一种是很方便的。
*如果需要一次动态地建立字典的一个字段,第二种比较合适
*第三种关键字形式所需的代码比常量少,【但是键必须是都是字符串才可行】
*如果需要在程序运行时把键和值逐步建成序列。第四中比较有用。
zip函数把程序运行动态获得的键和值列表合并在一起(例如分析数据文件字段)
如果所有键的值都相同,可以使用特殊形式对字典进行初始化。简单传入一个键列表,以及所有键的初始值(默认为空)
>>> dict.fromkeys(['a','b','c'],0)
{'a': 0, 'c': 0, 'b': 0}




作业

使用dict结构体完成班级花名册

通过名称查找到指定的人


myset=set([1,1,1,2,2,2,3,3,3,4,4,4,])

myset

{1,2,3,4}

myset.add(5)

myset

{1,2,3,4,5}

myset(1)

myset

{1,2,3,4,5,}

myset.remove(1)

myset

{2,3,4,5}



函数

>>>def myfunc(x,y):

print (x,y)

>>>myfunc(10,20

10 20

>>>myfunc("i love",111)

l love 111




<think>好的,用户的问题是想在Python中使用字典统计字符串中汉字和标点的数量。我需要仔细分析他的需求,并确保提供的方法正确且高效。 首先,用户提到了要统计汉字和标点的数量。根据之前的引用内容,汉字的范围是Unicode的\u4e00到\u9fa5,而标点符号可能需要单独处理。但用户没有明确标点的具体范围,可能需要考虑中文标点,比如,。!?等,或者更广泛的标点符号。这里需要明确如何区分汉字和标点。 参考用户提供的引用[2],其中提到使用正则表达式来匹配汉字,并且处理中文标点。可能需要用正则表达式来识别汉字和标点。用户之前的引用中有一个处理中文标点的集合,但具体标点范围可能需要进一步确定。例如,中文标点通常包括,。、;:‘’“”《》!?【】等,这些的Unicode范围可能比较分散,所以可能需要手动列出,或者使用其他方法。 接下来,用户想用字典来统计数量。通常的做法是遍历字符串中的每个字符,判断是否是汉字或标点,然后在对应的字典中增加计数。这里可能需要两个字典,一个存储汉字的计数,另一个存储标点的计数。或者,可以分开统计,但用户可能希望在一个结构中处理,或者分别统计。 根据引用[1],用户之前可能使用过字典推导式和count方法,但这里的场景不同,因为需要逐个字符检查。可能需要使用循环遍历每个字符,判断类型,然后更新字典。 考虑到效率问题,使用正则表达式可能会更高效。例如,用正则表达式找到所有汉字和标点,然后统计数量。但统计每个字符的出现次数的话,可能需要用到字典的get方法,或者使用collections模块中的Counter。 步骤分解: 1. 初始化两个字典,一个用于汉字,一个用于标点。 2. 遍历字符串中的每个字符。 3. 对于每个字符,判断是否是汉字:使用正则匹配或Unicode范围。 4. 如果是汉字,则更新汉字字典;否则,判断是否是标点,并更新标点字典。 5. 标点的判断可能需要一个集合,包含所有需要统计的标点符号。或者使用Unicode范围,但中文标点的范围可能不连续,所以手动列出可能更可靠。 例如,中文标点符号的Unicode范围可能包括:\u3000-\u303F,这是中文标点符号的主要范围。因此,可以用正则表达式来匹配。 所以,处理步骤可能如下: - 使用正则表达式匹配汉字:[一-龥]或者\u4e00-\u9fa5。 - 标点符号的范围可能是[\u3000-\u303F]以及其他可能的符号,比如!?等,可能需要根据具体需求调整。 但用户可能希望统计所有非汉字且非字母数字的字符作为标点,或者只特定的中文标点。需要明确这一点,但用户的问题中可能希望分开统计汉字和标点,而标点指的是中文标点。 因此,可能的解决步骤: 1. 导入re模块。 2. 定义正则表达式匹配汉字:hanzi_pattern = re.compile(r'[\u4e00-\u9fa5]') 3. 定义正则表达式匹配中文标点:可能使用[\u3000-\u303F]或其他范围。 例如,中文标点符号通常位于\u3000-\u303F,包括句号、逗号等。所以标点_pattern = re.compile(r'[\u3000-\u303F]') 4. 遍历字符串中的每个字符: - 如果匹配hanzi_pattern,则加入汉字字典。 - 如果匹配标点_pattern,则加入标点字典。 5. 统计各字典中的计数。 或者,可能更高效的方式是使用Counter,并筛选出符合条件的字符。 另外,用户可能需要同时统计汉字和标点,所以可以分开处理。例如: 对于每个字符: - 如果是汉字,统计到汉字字典。 - 如果是标点,统计到标点字典。 - 其他字符忽略,或者根据需求处理。 这样,可以用两个字典,或者使用两个Counter对象。 示例代码可能如下: import re from collections import defaultdict def count_chinese(s): hanzi_dict = defaultdict(int) punc_dict = defaultdict(int) hanzi_re = re.compile(r'[\u4e00-\u9fa5]') punc_re = re.compile(r'[\u3000-\u303F]') # 调整标点范围 for char in s: if hanzi_re.match(char): hanzi_dict[char] += 1 elif punc_re.match(char): punc_dict[char] += 1 return hanzi_dict, punc_dict 但用户可能希望将结果合并为一个字典,或者分开返回。不过根据问题描述,用户可能需要两个独立的字典。 另外,如果用户不需要区分不同标点符号,只需要总的标点数量,可以统计总数。但用户的问题可能要求每个标点的出现次数,所以用字典记录每个字符的次数。 不过,用户的问题明确说“统计汉字和标点的数量”,可能指的是统计各自的总数,还是每个字符的数量?需要进一步确认,但根据字典的结构,可能是每个字符的出现次数。 例如,输入字符串“你好,世界!”,汉字字典应包含'你':1, '好':1, '世':1, '界':1,标点字典包含',':1, '!':1。 或者,用户可能希望统计汉字的总数和标点的总数,即两个数字。但问题中的描述是“统计汉字和标点的数量”,而用字典的话,可能每个字符的计数。 需要明确这一点。例如,用户可能想要的是: 汉字总数:4,标点总数:2。或者每个汉字出现的次数和每个标点出现的次数。根据用户的问题描述中的例子,引用了之前的统计字符的方法,可能每个字符的计数,所以用字典存储每个汉字和标点的出现次数。 因此,代码可能需要两个字典,分别记录汉字和标点各字符的出现次数。 另外,用户可能需要考虑字符串中的其他字符,比如英文字母、数字等是否被排除。 例如,用户可能想忽略非汉字和非标点的字符。 现在,回到代码实现: 使用正则表达式来检测每个字符是否为汉字或中文标点。对于标点,可能需要更全面的正则表达式。例如,中文标点符号的范围可能包括\u3000-\u303F,\uFF00-\uFFEF中的部分符号,如“!”(\uFF01)、“”(\uFF08)等。因此,可能需要更广泛的正则表达式,或者手动列举。 或者,使用更广泛的标点匹配,比如使用unicodedata库中的category方法。例如,标点符号的Unicode类别包括P(标点符号),但中文标点可能属于不同的类别。例如,中文句号“。”属于Po(其他标点),而英文句号属于Pd(连接符?不确定)。这种方法可能更准确,但需要测试。 例如,可以使用unicodedata.category(char)来判断。标点符号的类别通常以'P'开头,比如 'Pc', 'Pd', 'Ps', 'Pe', 'Pi', 'Pf', 'Po'。因此,可以判断字符的类别是否以'P'开头,如果是,则视为标点。 但中文标点是否都被归类到这些类别中?例如,中文逗号“,”的category是'Po',而英文逗号是'Po'吗?可能需要测试。 例如,测试: import unicodedata print(unicodedata.category(',')) # 输出 'Po' print(unicodedata.category('. ')) # 输出 'Po' 所以,如果使用unicodedata,那么所有标点符号的category以'P'开头,但可能包括中英文标点。因此,如果用户希望仅统计中文标点,这种方法可能不够准确,因为英文标点也会被包括进去。 因此,可能需要结合两种方法:使用正则表达式来匹配中文标点的特定Unicode范围,而不是依赖category。 回到用户的问题,用户可能希望统计的是中文的标点,因此需要明确范围。根据引用[2],用户之前的处理可能涉及中文标点的集合,比如手动列出,或者使用特定范围。例如,引用[2]中提到的处理中文标点的大集合,可能包括多个Unicode码点。 因此,在代码中,可能需要将中文标点的Unicode范围明确写出,例如: 中文标点的范围可能包括: - \u3000-\u303F:包含常用的标点如、。〃〄々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〘〙〚〛〜〝〞〟〠〡〢〣〤〥〦〧〨〩〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿 这可能覆盖大部分中文标点符号。 因此,正则表达式模式可以是r'[\u3000-\u303F]'。但是否足够?比如,中文的感叹号“!”是\uFF01,属于半角符号的全角版本,可能不在这个范围内。例如,全角的“!”是\uFF01,而半角的是\u0021。因此,如果用户的字符串中包含全角的中文标点,比如“!”,则上述正则表达式无法匹配到。 这可能是一个问题。例如,用户输入的字符串中的标点可能是全角的,比如“你好!”,这里的感叹号是全角的话,属于\uFF01,不在\u3000-\u303F范围内。因此,需要将标点的正则表达式扩展到这个范围。 所以,可能需要调整正则表达式,以包含更多的Unicode范围。例如: 标点正则表达式可能包括: - \u3000-\u303F - \uFF00-\uFF0F(全角符号) - \uFF1A-\uFF20 - \uFF3B-\uFF40 - \uFF5B-\uFF65 这些范围可能覆盖更多的全角标点符号,如! (\uFF01)、?(\uFF1F)、:(\uFF1A)、;(\uFF1B)、(\uFF08)等。 不过,这样的正则表达式可能会比较复杂。或者,可以手动列举常用的中文标点符号,比如: ,。、;:?!“”‘’()《》【】…—~·〈〉「」『』〖〗〔〕() 但手动列举可能比较麻烦,容易遗漏。因此,更可靠的方式是查找中文标点的Unicode范围,或者使用更广泛的正则表达式。 例如,全角标点符号位于\uFF00-\uFFEF范围内,但需要具体筛选。例如,全角的感叹号是\uFF01,问号是\uFF1F,逗号\uFF0C,句号\uFF0E,等等。因此,可能需要将这些包含在标点的正则表达式中。 因此,标点的正则表达式可能写成: punc_re = re.compile(r'[\u3000-\u303F\uFF00-\uFF0F\uFF1A-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65]') 但需要验证这些范围是否准确覆盖了常用的中文标点。 这可能比较复杂,所以为了简化,可以查阅中文标点的Unicode码点,并构建相应的正则表达式。 例如,以下是一些常见中文标点的Unicode码点: - \u3001:顿号、 - \u3002:句号。 - \u3003:〃 - \u3008-\u3011:〈〉《》「」『』【】 - \u3014-\u301B:〔〕〖〗〘〙〚〛 - \uFF01:! - \uFF08:( - \uFF09:) - \uFF0C:, - \uFF1A:: - \uFF1B:; - \uFF1F:? - \uFF0E:. - 等等。 因此,可能需要将这些码点包含在正则表达式中。或者,可以使用更广泛的范围,比如: punc_re = re.compile(r'[,。!?、;:“”‘’()《》【】…—~·]') 但这种方式需要手动添加所有可能的标点,可能会遗漏。 因此,可能更高效的方式是结合多个Unicode范围,以覆盖大部分中文标点。 经过查找资料,中文标点符号的Unicode范围大致包括: - \u3000-\u303F:CJK符号和标点 - \uFE30-\uFE4F:中日韩兼容形式(包括一些全角标点) - \uFF00-\uFFEF:半角及全角形式(包含全角标点) 例如,全角的逗号(,)是\uFF0C,位于\uFF00-\uFFEF范围。因此,可能需要将标点正则表达式调整为: punc_re = re.compile(r'[\u3000-\u303F\uFF00-\uFF0F\uFF1A-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65\uFE30-\uFE4F]') 这样可能覆盖更多的中文标点符号。不过,这样可能包含一些不需要的字符,比如全角数字或字母,所以需要仔细调整。 这可能变得过于复杂。另一种方法是使用unicodedata的category,并结合是否为中文字符之外的标点。例如,判断字符是否为标点,且不是汉字。 例如,代码可以这样写: import unicodedata def is_chinese_punctuation(char): # 判断是否为标点且属于中文标点范围 category = unicodedata.category(char) if category.startswith('P'): # 进一步判断是否在常用中文标点范围内 # 例如,排除英文的标点,但可能难以准确判断 # 或者结合Unicode码点范围 cp = ord(char) if ((cp >= 0x3000 and cp <= 0x303F) or (cp >= 0xFF00 and cp <= 0xFFEF) or (cp >= 0xFE30 and cp <= 0xFE4F)): return True return False 然后,在遍历每个字符时,如果is_chinese_punctuation(char)返回True,则视为中文标点。 这种方法可能更准确,但需要编写较多的条件判断。 不过,这可能超出了用户当前的需求范围。用户可能只需要基础的统计,所以可以暂时采用简单的正则表达式,比如匹配\u3000-\u303F和\uFF00-\uFF0F等范围中的标点。 现在,回到用户的代码示例。用户可能希望得到一个字典,其中键是汉字或标点,值是对应的出现次数。 因此,代码的大致结构可能是: import re from collections import defaultdict def count_chinese_and_punctuation(s): hanzi_dict = defaultdict(int) punc_dict = defaultdict(int) # 正则表达式匹配汉字 hanzi_pattern = re.compile(r'[\u4e00-\u9fa5]') # 正则表达式匹配中文标点 punc_pattern = re.compile(r'[\u3000-\u303F\uff00-\uff0f\uff1a-\uff20\uff3b-\uff40\uff5b-\uff65]') for char in s: if hanzi_pattern.fullmatch(char): hanzi_dict[char] += 1 elif punc_pattern.fullmatch(char): punc_dict[char] += 1 return hanzi_dict, punc_dict 然后,用户可以将结果转换为普通字典,并按需求排序或输出。 测试一下: s = "你好,世界!今天天气怎么样?" hanzi, punc = count_chinese_and_punctuation(s) print("汉字统计:", dict(hanzi)) print("标点统计:", dict(punc)) 预期结果: 汉字统计: {'你':1, '好':1, '世':1, '界':1, '今':1, '天':1, '气':1, '怎':1, '么':1, '样':1} 标点统计: {',':1, '!':1, '?':1} 但这里的标点是否被正确识别?例如,全角的“!”是\uff01,是否在正则表达式的范围内? 正则表达式中的punc_pattern是[\u3000-\u303F\uff00-\uff0f\uff1a-\uff20\uff3b-\uff40\uff5b-\uff65] \uff00-\uff0f 包括\uff00到\uff0f,其中\uff01是感叹号,属于这个范围。而\uff1a-\uff20包括冒号到@符号的位置?可能包括\uff1a(:)、\uff1b(;)、\uff1f(?)等。例如,?是\uff1f,所以在\uff1a-\uff20范围内(1a到20是十六进制)。而\uff5b-\uff65包括{到・,比如{}等,可能不需要。所以可能需要调整正则表达式,以确保覆盖所有需要的中文标点。 或者,更简单的做法是使用两个范围:\u3000-\u303F 和 \uff00-\uffef,但这样可能包含其他字符,比如全角数字或字母。所以需要更精确。 可能更准确的正则表达式为: punc_pattern = re.compile(r'[\u3000-\u303F\uff01-\uff0f\uff1a-\uff20\uff5b-\uff65]') 这样,可以覆盖: - \u3000-\u303F:CJK符号和标点 - \uff01-\uff0f:全角标点如!"#$%&'()*+,-./ - \uff1a-\uff20::;<=>?@ - \uff5b-\uff65:{|}~⦅⦆。「」、・ 可能覆盖了大部分中文标点,但可能需要进一步调整。 不过,这样的正则表达式可能仍然不够全面,但对于大多数情况来说足够使用。 综上,代码的大致思路是: 1. 使用正则表达式识别汉字和中文标点。 2. 遍历字符串中的每个字符。 3. 根据正则表达式判断字符类型,并更新对应的字典。 此外,用户可能需要使用字典推导式或者Counter来简化代码,例如: from collections import Counter def count_chinese_and_punctuation(s): hanzi = Counter() punc = Counter() hanzi_re = re.compile(r'^[\u4e00-\u9fa5]$') punc_re = re.compile(r'^[\u3000-\u303F\uff00-\uff0f\uff1a-\uff20\uff5b-\uff65]$') for char in s: if hanzi_re.match(char): hanzi[char] += 1 elif punc_re.match(char): punc[char] += 1 return hanzi, punc 这里使用Counter可以简化计数的过程。 在测试时,如果输入的字符串包含混合的汉字和标点,例如:“你好,世界!”,则汉字字典将包含'你'、'好'、'世'、'界'各1次,标点字典将包含','和'!'各1次。 用户可能需要将结果进行排序,例如按照出现次数降序排列。可以使用sorted函数,如引用[1]中的例子: sorted_hanzi = sorted(hanzi.items(), key=lambda x: x[1], reverse=True) sorted_punc = sorted(punc.items(), key=lambda x: x[1], reverse=True) 这样用户可以得到排序后的结果。 总结,用户的解决方案需要: - 使用正则表达式正确匹配汉字和中文标点。 - 遍历字符串,统计各字符出现次数。 - 返回两个字典,分别记录汉字和标点的出现次数。 可能的代码实现如下: import re from collections import defaultdict def count_chinese_and_punct(text): # 初始化字典 hanzi = defaultdict(int) punct = defaultdict(int) # 编译正则表达式 hanzi_re = re.compile(r'[\u4e00-\u9fa5]') # 匹配汉字 punct_re = re.compile( r'[' # 开始字符集 r'\u3000-\u303F' # CJK标点符号 r'\uff00-\uff0f' # 全角标点1 r'\uff1a-\uff20' # 全角标点2 r'\uff5b-\uff65' # 全角标点3 r']' ) # 遍历字符 for char in text: if hanzi_re.fullmatch(char): hanzi[char] += 1 elif punct_re.fullmatch(char): punct[char] += 1 return dict(hanzi), dict(punct) # 示例用法 s = "你好,世界!今天天气怎么样?" hanzi_dict, punct_dict = count_chinese_and_punct(s) print("汉字统计:", hanzi_dict) print("标点统计:", punct_dict) 但需要验证正则表达式是否能正确匹配所有中文标点。例如,全角逗号(\uff0c)、句号(\u3002)、感叹号(\uff01)、问号(\uff1f)等是否在正则表达式范围内。 正则表达式中的punct_re的字符集包括: - \u3000-\u303F:包括中文句号、逗号、顿号、括号等。 - \uff00-\uff0f:包括!"#$%&'()*+,-./等全角符号,其中逗号是\uff0c,句号是\uff0e,括号是\uff08、\uff09。 - \uff1a-\uff20:包括:;<=>?@,其中?是\uff1f。 - \uff5b-\uff65:包括{|}~等,可能包括波浪号~(\uff5e)。 因此,常见的全角标点符号应该被覆盖。 测试字符串中的“,”是\uff0c,属于\uff00-\uff0f范围,所以会被匹配。而“!”是\uff01,同样属于该范围。问号“?”是\uff1f,属于\uff1a-\uff20范围吗?\uff1a到\uff20的十六进制范围是1A到20,即十进制的26到32。而\uff1f是31,所以属于该范围。所以会被匹配。 因此,上述正则表达式应该可以正确匹配大部分中文标点。 在示例中,字符串“你好,世界!今天天气怎么样?”中的标点“,”和“!”、“?”都会被统计到。 因此,这段代码应该能满足用户的需求。 最后,用户可能希望将结果进行排序,可以按照引用[1]中的方法,使用sorted函数: sorted_hanzi = sorted(hanzi_dict.items(), key=lambda x: x[1], reverse=True) sorted_punct = sorted(punct_dict.items(), key=lambda x: x[1], reverse=True) 用户可以根据需要输出结果。</think>在Python中统计字符串中的汉字和标点数量,可以通过正则表达式匹配字符类别并结合字典计数实现。以下是分步解决方案: --- ### 实现步骤 1. **定义正则表达式**: - 汉字范围:`\u4e00-\u9fa5` - 中文标点范围:覆盖CJK标点符号(`\u3000-\u303F`)和全角标点(`\uff00-\uff0f`等) 2. **遍历字符串**,判断每个字符是否为汉字或标点,并统计到对应字典。 3. **使用字典推导式或`defaultdict`**记录每个字符的出现次数。 --- ### 完整代码 ```python import re from collections import defaultdict def count_chinese_and_punct(text): hanzi = defaultdict(int) # 存储汉字统计 punct = defaultdict(int) # 存储标点统计 # 正则表达式匹配汉字和中文标点 hanzi_re = re.compile(r'^[\u4e00-\u9fa5]$') punct_re = re.compile( r'^[\u3000-\u303F' # CJK标点符号 r'\uff00-\uff0f' # 全角标点1(如!,。等) r'\uff1a-\uff20' # 全角标点2(如:;等) r'\uff5b-\uff65' # 全角标点3(如{}等) r']$' ) # 遍历字符并分类统计 for char in text: if hanzi_re.match(char): hanzi[char] += 1 elif punct_re.match(char): punct[char] += 1 return dict(hanzi), dict(punct) # 示例用法 text = "你好,世界!今天天气怎么样?" hanzi_dict, punct_dict = count_chinese_and_punct(text) print("汉字统计:", hanzi_dict) print("标点统计:", punct_dict) ``` --- ### 代码说明 1. **正则表达式**: - `hanzi_re`匹配所有汉字字符。 - `punct_re`覆盖常见中文标点符号,包括全角逗号(`,`)、句号(`.`)、感叹号(`!`)等[^2]。 2. **字典统计**: - 使用`defaultdict`简化计数逻辑,自动初始化未出现的键。 - 遍历字符串时,通过正则判断字符类型并更新对应字典。 3. **输出结果**: - 返回普通字典格式,可直接查看每个字符的出现次数。 --- ### 示例结果 对于输入`"你好,世界!今天天气怎么样?"`,输出: ``` 汉字统计: {'你':1, '好':1, '世':1, '界':1, '今':1, '天':2, '气':1, '怎':1, '么':1, '样':1} 标点统计: {',':1, '!':1, '?':1} ``` --- ### 扩展功能 若需按出现次数排序,可使用`sorted`函数: ```python sorted_hanzi = sorted(hanzi_dict.items(), key=lambda x: x[1], reverse=True) sorted_punct = sorted(punct_dict.items(), key=lambda x: x[1], reverse=True) print("按频率排序的汉字:", sorted_hanzi) print("按频率排序的标点:", sorted_punct) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值