Learning-Python【21】:Python常用模組(4)—— re、logging、hashlib、subprocess
re 模組:與正則相關的模組
在使用 re 模組之前,需要先了解正則表示式(regular expression),描述了一種字串匹配的模式(pattern),可以用來檢查一個字串是否含有某個子字串、將匹配的子字串替換或者從某個字串中取出符合某個條件的子字串等。
import re
# \w 匹配字母數字及下劃線
print(re.findall('\w','hello 123_ */-='))
# \W 匹配非字母數字下劃線
print(re.findall('\W','hello 123_ */-='))
# \s 匹配任意空白字元, 等價於(空格, \n, \t, \r, \f)
print(re.findall('\s','hell\no 12\t3_ */-='))
# \S 匹配任意非空字元
print(re.findall('\S','hell\no 12\t3_ */-='))
# \d 匹配任意數字, 等價於(0--9)
print(re.findall('\d','hell\no 12\t3_ */-='))
# \D 匹配任意非數字
print(re.findall('\D','hell\no 12\t3_ */-='))
# \n 匹配換行符
print(re.findall('\n','hell\no 1\n2\t3_ */-= '))
# \t 匹配製表符
print(re.findall('\t','hell\no 12\t3_ */-='))
# ^ 匹配字串的開頭
print(re.findall('qiu', 'my name is qiu, qiu like music'))
print(re.findall('^qiu', 'my name is qiu, qiu like music'))
print(re.findall('^qiu', 'qiu my name is qiu, qiu like music'))
# $ 匹配字串的結尾, 不匹配末尾的換行符
print(re.findall(' qiu$', 'qiu my name is qiu, qiu like qiu'))
print("=" * 50)
# 重複匹配
# . 代表匹配換行符以外的任意一個字元
print(re.findall('a.c', 'abc a*c a\ncfdsa cds alc a+c a\tcdjsh')) # ['abc', 'a*c', 'a c', 'alc', 'a+c']
# 如果想匹配換行符, re.DOTALL, 匹配點所有的字元
print(re.findall('a.c', 'abc a*c a\ncfdsa cds alc a+c a\tcdjsh',re.DOTALL))
# 匹配換行符以外的任意兩個字元
print(re.findall('a..c', 'abc alc aac asd aaaaac a *c a+c adsadsa ='))
print(re.findall('a.c', 'abc alc aac aAc aBc asd aaaaac a *c a+c a-c a/c adsadsa = a1c a2c'))
# [] 代表匹配一個字元, 該字元屬於中括號內指定的字元
# 取出a.c之間是小寫字母的字串
print(re.findall('a[a-z]c', 'abc alc aac aAc aBc asd aaaaac a *c a+c a-c a/c adsadsa = a1c a2c'))
# 取出a.c之間是大寫字母的字串
print(re.findall('a[A-Z]c', 'abc alc aac aAc aBc asd aaaaac a *c a+c a-c a/c adsadsa = a1c a2c'))
# 取出a.c之間只要+-*/ (注意: -只能放在首或尾, 放中間是連線符號, 一定要放中間則使用轉義字元 \-)
print(re.findall('a[-+/*]c', 'abc alc aac aAc aBc asd aaaaac a *c a+c a-c a/c adsadsa = a1c a2c'))
print(re.findall('a[+\-/*]c', 'abc alc aac aAc aBc asd aaaaac a *c a+c a-c a/c adsadsa = a1c a2c'))
# ^放在[]內表示取反, 除了小寫字母都可以取出
print(re.findall('a[^a-z]c', 'abc alc aac aAc aBc asd aaaaac a *c a+c a-c a/c adsadsa = a1c a2c'))
print("=" * 50)
# * ? + {n,m} 都不能單獨使用, 必須與其他字元連用
# * 代表*左側的字元出現0次或無窮次
print(re.findall('ab*', 'a ab abbb abbbb a1bbbb a-123'))
# 有b就獲取, 有多少b就獲取多少, 沒有就獲取匹配到的
# ['a', 'ab', 'abbb', 'abbbb', 'abbbb', 'a', 'a']
# 也可以用{n,m}表示0到無窮次
print(re.findall('ab{0,}', 'a ab abbb abbbb a1bbbb a-123'))
print("=" * 50)
# ? 代表?左側的字元出現0次或1次
print(re.findall('ab?', 'a ab abbb abbbb a1bbbb a-123'))
# 有b就獲取, 不管有多少b只獲取一個, 沒有就獲取匹配到的
# ['a', 'ab', 'ab', 'ab', 'a', 'a']
# 也可以用{n,m}表示0到1次
print(re.findall('ab{0,1}', 'a ab abbb abbbb a1bbbb a-123'))
print("=" * 50)
# + 代表+左側的字元出現1次或無窮次
print(re.findall('ab+', 'a ab abbb abbbb a1bbbb a-123'))
# 有b就獲取, 有多少b就獲取多少, 沒有就不獲取
# ['ab', 'abbb', 'abbbb']
# 也可以用{n,m}表示1到無窮次
print(re.findall('ab{1,}', 'a ab abbb abbbb a1bbbb a-123'))
print("=" * 50)
# {n,m} 左側的字元最少匹配n次且最多匹配m次, n <= m
print(re.findall('ab{1,3}', 'a ab abbb abbbb a1bbbb a-123'))
# ['ab', 'abbb', 'abbb']
print("=" * 50)
# .* 貪婪匹配, 任意個數任意字元
print(re.findall('a.*c', 'ab123dsac32155sdadasc'))
# .*? 非貪婪匹配
print(re.findall('a.*?c', 'ab123dsac32155sdadasc'))
# () 分組
print(re.findall('expression=".*"','expression="1+2+3/4*5" qiu="beautiful"'))
print(re.findall('expression=".*?"','expression="1+2+3/4*5" qiu="beautiful"'))
print(re.findall('(expression)=".*?"','expression="1+2+3/4*5" qiu="beautiful"'))
# 取出表示式1+2+3/4*5
print(re.findall('expression="(.*?)"','expression="1+2+3/4*5" qiu="beautiful"'))
# 取出網址https://www.qiuxirufeng.com
print(re.findall('href="(.*?)"','<p>段落</p><a href="https://www.baidu.com">點我啊</a><h1>標題</h1><a href="https://www.qiuxirufeng.com">點我啊</a>'))
# a|b 取a或b
print(re.findall('a|b', 'ab123adbhsga'))
# 取出和公司相關的單詞
print(re.findall('companies|company', 'Too many companies have gone bankrupt, and the next one is my company'))
# ['ies', 'y']
print(re.findall('compan(ies|y)', 'Too many companies have gone bankrupt, and the next one is my company'))
# ?: 取出的內容並非組內的內容, 而是包含外面的 ['companies', 'company']
print(re.findall('compan(?:ies|y)', 'Too many companies have gone bankrupt, and the next one is my company'))
# 取 a\c
# r'a\\c' 先交給python直譯器識別, 識別為'a\\c', 再交給re模組識別, 識別為'a\c'
print(re.findall(r'a\\c', 'a\c alc aAc aac'))
# 'a\\\\c', 先交給python直譯器識別, 識別為'a\\c', 再交給re模組識別, 識別為'a\c'
print(re.findall('a\\\\c', 'a\c alc aAc aac'))
正則表示式
# -*- coding: utf-8 -*-
import re
print(re.findall('qiu', 'qiu like music, qiu like folk music'))
# search只匹配一個, 有就返回一個物件, 沒有就返回None
print(re.search('qiu', 'qiu like music, qiu like folk music'))
# 想要取結果, 後面需要加上group()方法
print(re.search('qiu', 'qiu like music, qiu like folk music').group())
print(re.findall('qi(u)', 'qiu like music, qiu like folk music'))
print(re.search('qi(u)', 'qiu like music, qiu like folk music').group())
print("=" * 50)
print(re.search('qiu', '123qiu like music, qiu like folk music'))
# match是從頭開始找, 相當於search在匹配中加上^
print(re.match('qiu', '123qiu like music, qiu like folk music'))
print(re.search('^qiu', '123qiu like music, qiu like folk music'))
print("=" * 50)
li = 'qiu:22:male'.split(":")
print(li)
# 將字串以:和空格切分
l1 = re.split(':| ', 'qiu:22:male xxx')
print(l1)
print("=" * 50)
# 將qiu替換成xi, 可以指定替換次數
print(re.sub('qiu', 'xi', 'qiu is nice, qiu qiu qiu'))
print(re.sub('qiu', 'xi', 'qiu is nice, qiu qiu qiu', 1))
# 把所有以xx結尾的都替換成qiu
s = 'lxx is good, lllxx wxx cxx are good'
print(re.sub('[a-z]+xx','qiu', s))
print("=" * 50)
# print(re.findall('qiu', 'qiu like music, qiu like folk music'))
# print(re.search('qiu', 'qiu like music, qiu like folk music').group())
pattern = re.compile('qiu')
print(pattern.findall('qiu like music, qiu like folk music'))
print(pattern.search('qiu like music, qiu like folk music'))
re模組的使用
logging 模組:與日誌相關操作的模組
logging模組主要可以根據自定義日誌資訊,在程式執行的時候將日誌列印在終端及記錄日誌到檔案中。logging支援的日誌有五個級別:
debug() 除錯級別,一般用於記錄程式執行的詳細資訊,對應數字級別10
info() 事件級別,一般用於記錄程式的執行過程,對應數字級別20
warnning() 警告級別,,一般用於記錄程式出現潛在錯誤的情形,對應數字級別30
error() 錯誤級別,一般用於記錄程式出現錯誤,但不影響整體執行,對應數字級別40
critical() 嚴重錯誤級別 , 出現該錯誤已經影響到整體執行,對應數字級別50
# 日誌級別遵循原則: 自下而上進行匹配
# debug --> info --> warning --> error --> critical
logging.debug('除錯資訊')
logging.info('正常資訊')
logging.warning('警告資訊')
logging.error('錯誤資訊')
logging.critical('嚴重錯誤資訊')
# 執行輸出
WARNING:root:警告資訊
ERROR:root:錯誤資訊
CRITICAL:root:嚴重錯誤資訊
簡單用法,將日誌列印到終端
但是這樣的輸出存在一定的問題:
1、沒有指定日誌級別
2、沒有指定日誌格式
3、只能在螢幕上列印,沒有寫入檔案
所以要進行基本的日誌配置
可在logging.basicConfig()函式中可通過具體引數來更改logging模組預設行為,可用引數有:
filename:用指定的檔名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被儲存在指定的檔案中。
filemode:檔案開啟方式,在指定了filename時使用這個引數,預設值為“a”還可指定為“w”。
format:指定handler使用的日誌顯示格式。
datefmt:指定日期時間格式。
level:設定rootlogger(後邊會講解具體概念)的日誌級別
stream:用指定的stream建立StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者檔案,預設為sys.stderr。若同時列出了filename和stream兩個引數,則stream引數會被忽略。
format引數中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 數字形式的日誌級別
%(levelname)s 文字形式的日誌級別
%(pathname)s 呼叫日誌輸出函式的模組的完整路徑名,可能沒有
%(filename)s 呼叫日誌輸出函式的模組的檔名
%(module)s 呼叫日誌輸出函式的模組名
%(funcName)s 呼叫日誌輸出函式的函式名
%(lineno)d 呼叫日誌輸出函式的語句所在的程式碼行
%(created)f 當前時間,用UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌資訊時的,自Logger建立以 來的毫秒數
%(asctime)s 字串形式的當前時間。預設格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
%(thread)d 執行緒ID。可能沒有
%(threadName)s 執行緒名。可能沒有
%(process)d 程序ID。可能沒有
%(message)s使用者輸出的訊息
基本的日誌配置
import logging
# 進行基本的日誌配置
logging.basicConfig(filename='access.log',
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=10)
logging.debug('除錯資訊')
logging.info('正常資訊')
logging.warning('警告資訊')
logging.error('錯誤資訊')
logging.critical('嚴重錯誤資訊')
# 執行後結果存放在檔案中(以GBK的格式存入檔案)
2018-10-21 08:43:53 - root - DEBUG - logging模組: 除錯資訊
2018-10-21 08:43:53 - root - INFO - logging模組: 正常資訊
2018-10-21 08:43:53 - root - WARNING - logging模組: 警告資訊
2018-10-21 08:43:53 - root - ERROR - logging模組: 錯誤資訊
2018-10-21 08:43:53 - root - CRITICAL - logging模組: 嚴重錯誤資訊
View Code
現在解決了上面出現的三個問題,但是又出現了新的問題:
1、不能指定字元編碼
2、只能在檔案中列印
basicConfig 引數有一個方法叫 stream,設定為 True 會提示不能同時列印到螢幕和檔案裡,寫入檔案中的資訊目前只能將檔案的字元編碼修改為GBK
import logging
# 進行基本的日誌配置
logging.basicConfig(filename='access.log',
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=10,
stream=True
)
logging.debug('除錯資訊')
logging.info('正常資訊')
logging.warning('警告資訊')
logging.error('錯誤資訊')
logging.critical('嚴重錯誤資訊')
# 執行後輸出
Traceback (most recent call last):
File "E:/Python日誌模組的使用/logging模組.py", line 10, in <module>
stream=True
File "D:\Program Files\Python36\lib\logging\__init__.py", line 1797, in basicConfig
raise ValueError("'stream' and 'filename' should not be "
ValueError: 'stream' and 'filename' should not be specified together
View Code
logging模組包含四種角色:logger,filter,formatter,handler
logger 負責產生日誌資訊,filter 負責篩選日誌,這一步不是我們所需要處理的,formatter 用來控制日誌的輸出格式,handler 負責日誌輸出的目標,然後通過繫結 logger 物件與 handler 物件,讓產生的日誌資訊能夠同時在檔案和控制檯上列印輸出,接著繫結 handler 物件與 formatter 物件,讓輸出資訊按照指定的格式輸出,最後設定日誌級別,可以在 logger 與 handler兩層關卡進行設定
import logging
# 1. logger: 負責產生日誌資訊
logger1 = logging.getLogger('交易日誌')
# 2. filter: 負責篩選日誌
# 這一步無需我們操作
# 3. formatter: 控制日誌的輸出格式
formatter1 = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %X')
formatter2 = logging.Formatter(fmt='%(asctime)s - %(message)s',
datefmt='%Y-%m-%d %X')
# 4. handler: 負責日誌輸出的目標
# 在檔案中列印
h1 = logging.FileHandler(filename='a1.log', encoding='utf-8')
h2 = logging.FileHandler(filename='a2.log', encoding='utf-8')
# 在控制檯輸出
s = logging.StreamHandler()
# 5. 繫結logger物件與handler物件
# 讓產生的logger1分別有三種輸出物件, 能夠同時在檔案和控制檯中列印輸出
logger1.addHandler(h1)
logger1.addHandler(h2)
logger1.addHandler(s)
# 6. 繫結handler物件與formatter物件
# 三種輸出物件在列印時需要按照某種格式輸出
h1.setFormatter(formatter1)
h2.setFormatter(formatter1)
s.setFormatter(formatter2)
# 7. 設定日誌級別, 可以在logger與handler兩層關卡進行設定
# logger1.setLevel(30) # 這裡第一層關卡設定30已經卡死, 後面再設定輸出都無效
logger1.setLevel(10)
h1.setLevel(10)
h2.setLevel(10)
s.setLevel(10)
logger1.info('qiu轉賬給xi一個億')
logging模組的四種角色
上面這個寫法步驟有些繁瑣,所以有一個寫好的配置檔案,使用的時候通過執行檔案直接匯入即可
# -*- coding: utf-8 -*-
# 定義三種日誌輸出格式
standard_format = '%(asctime)s - %(filename)s - 第%(lineno)d行 - %(name)s - %(levelname)s - %(message)s'
simple_format = '%(asctime)s - %(levelname)s - %(message)s'
id_simple_format = '%(asctime)s - %(message)s'
# log檔案的全路徑
logfile_path1 = r'E:\Python\Python Fullstack\day22\日誌模組的使用\a1.log'
logfile_path2 = r'E:\Python\Python Fullstack\day22\日誌模組的使用\a2.log'
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'formatter1': {
'format': standard_format
},
'formatter2': {
'format': simple_format
},
},
'filters': {},
'handlers': {
# 列印到終端的日誌
's': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 列印到螢幕
'formatter': 'formatter2'
},
# 列印到檔案的日誌, 收集info及以上的日誌
'h1': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 儲存到檔案
'formatter': 'formatter1',
'filename': logfile_path1, # 日誌檔案
'encoding': 'utf-8', # 日誌檔案的編碼
},
'h2': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 儲存到檔案
'formatter': 'formatter1',
'filename': logfile_path2, # 日誌檔案
'encoding': 'utf-8', # 日誌檔案的編碼
},
},
'loggers': {
'logger1': {
'handlers': ['h1', 'h2', 's'], # 這裡把上面定義的兩個handler都加上,即log資料既寫入檔案又列印到螢幕
'level': 'DEBUG',
'propagate': False, # 向上(更高level的logger)傳遞
},
},
}
logging配置檔案
import settings
import logging.config
logging.config.dictConfig(settings.LOGGING_DIC) # 匯入上面定義的logging配置
logger1 = logging.getLogger('logger1')
logger1.debug("除錯日誌")
執行檔案
上面這個只能獲取 logger1 的資訊,因為此時只定義一個 logger1 ,但當需要記錄的日誌檔案多起來,就需要獲取多個日誌檔案,因此這裡不能寫死,可以在配置檔案中將其定義為空,任意指定配置名,但獲取的都是相同配置
# -*- coding: utf-8 -*-
# 定義三種日誌輸出格式
standard_format = '%(asctime)s - %(filename)s - 第%(lineno)d行 - %(name)s - %(levelname)s - %(message)s'
simple_format = '%(asctime)s - %(levelname)s - %(message)s'
id_simple_format = '%(asctime)s - %(message)s'
# log檔案的全路徑
logfile_path1 = r'E:\Python\Python Fullstack\day22\日誌模組的使用\a1.log'
logfile_path2 = r'E:\Python\Python Fullstack\day22\日誌模組的使用\a2.log'
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'formatter1': {
'format': standard_format
},
'formatter2': {
'format': simple_format
},
},
'filters': {},
'handlers': {
# 列印到終端的日誌
's': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 列印到螢幕
'formatter': 'formatter2'
},
# 列印到檔案的日誌, 收集info及以上的日誌
'h1': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 儲存到檔案
'formatter': 'formatter1',
'filename': logfile_path1, # 日誌檔案
'encoding': 'utf-8', # 日誌檔案的編碼
},
'h2': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 儲存到檔案
'formatter': 'formatter1',
'filename': logfile_path2, # 日誌檔案
'encoding': 'utf-8', # 日誌檔案的編碼
},
},
'': {
# 將其定義為空
'': {
'handlers': ['h1', 'h2', 's'], # 這裡把上面定義的兩個handler都加上,即log資料既寫入檔案又列印到螢幕
'level': 'DEBUG',
'propagate': False, # 向上(更高level的logger)傳遞
},
},
}
logging配置檔案
# -*- coding: utf-8 -*-
import settings
import logging.config
logging.config.dictConfig(settings.LOGGING_DIC) # 匯入上面定義的logging配置
logger1 = logging.getLogger('使用者相關')
logger2 = logging.getLogger('交易日誌')
logger1.info("除錯日誌")
logger2.info('qiu轉賬給xi一個億')
執行檔案
hashlib 模組:用來進行 hash 或者 md5 加密,且這種加密是不可逆的
hash:是一種演算法,該演算法接受傳入的內容,經過運算得到一串 hash 值,如果把 hash 演算法比喻為一座工廠,那傳給 hash 演算法的內容就是原材料,生成的 hash 值就是生產出的產品
hash 值有三大特性:
1、只要傳入的內容一樣,得到的 hash 值必然一樣
2、只要我們使用的 hash 演算法固定,無論傳入的內容有多大,得到的hash值的長度是固定的
3、不可以用 hash 值逆推出原來的內容
基於 1 和 2 可以在下載檔案時做檔案一致性校驗,基於 1 和 3 可以對密碼進行加密
import hashlib
# 1. 造出hash工廠
m = hashlib.md5()
# 2、運送原材料
m.update('你好啊'.encode('utf-8'))
m.update('啊哈'.encode('utf-8'))
# 3、產出hash值
print(m.hexdigest()) # a4be72e57bc198333ed98188c48b2f85
# ==================================================================
# 1、造出hash工廠
m = hashlib.md5('你'.encode('utf-8'))
# 2、運送原材料
m.update('好啊啊哈'.encode('utf-8'))
# 3、產出hash值
print(m.hexdigest()) # a4be72e57bc198333ed98188c48b2f85
# ==================================================================
# 應用一:檔案一致性校驗
# 1、造出hash工廠
m = hashlib.sha512('你'.encode('utf-8'))
# 2、運送原材料
m.update('好啊sadfsadf啊哈asdfsafdadsadsadfsadfsadfsadfasdff的張銘言'.encode('utf-8'))
# 3、產出hash值
print(m.hexdigest())
# 977c7a4f13e76f3f026e45540c72c6ba5dbfc41357bc452fba9d9824b71c5e074298c3f62f57c6a42dd769e6a03c26be44742e4e77f284e19c106e7fba3093da
# ===================================================================
# 1、造出hash工廠
m = hashlib.md5()
# 2、運送原材料
with open(r'E:\01.mp4','rb') as f:
for line in f:
m.update(line)
# 3、產出hash值
print(m.hexdigest())
# b5672ac47a068231f2c56da5df652f47
hashlib模組
密碼加鹽:對現有的密碼進行處理,比如加一行文字,再對齊所有內容進行加密
password = input('>>>: ')
m = hashlib.md5()
m.update('天王蓋地虎'.encode('utf-8'))
m.update(password.encode('utf-8'))
print(m.hexdigest())
密碼加鹽
Python 還有一個 hmac 模組,它內部對我們建立 key 和內容進行進一步的處理然後再加密
import hmac
m = hmac.new('小雞燉蘑菇'.encode('utf-8'))
m.update('hello'.encode('utf-8'))
print(m.hexdigest())
hmac
subprocess 模組:用來執行系統命令
subprocess 是子程序,匯入模組使用 subprocess 的 Popen() 方法呼叫 shell 終端執行 tasklist 命令用來顯示執行在本地計算機上的所有程序,但是這時執行的 Python 程式相當於一個父程序,在子程序還沒有執行結束父程序便已經結束,所以無法顯示結果,可以通過 time 模組讓 Python 程式睡眠一段時間,從而檢視 subprocess 的執行結果
import time
import subprocess
subprocess.Popen("tasklist", shell=True)
time.sleep(3)
View Code
但是上面只能輸出在控制檯,倘若要輸出到檔案或者別的地方,所以在子程序與父程序之間要建立一個共享資料的地方,叫做管道,且是在記憶體中建立。當使用這些資料時,直接從管道中取,當然取出的是正確的資料,因為這是正確的管道。對於上面來說,命令有可能輸入錯誤,於是還有錯誤的資料,所以應該再使用一個存放錯誤資料的管道,這樣在取資料的時候就有了區分,得到的結果也可以做存放於檔案的操作
import subprocess
obj = subprocess.Popen("tasklist",
shell=True,
# 正確資料的管道
stdout=subprocess.PIPE,
# 錯誤資料的管道
stderr=subprocess.PIPE)
stdout_res = obj.stdout.read()
print(stdout_res.decode('gbk'))
# 如果輸入錯誤的命令,則使用下面的程式碼
# stderr_res = obj.stderr.read()
# print(stderr_res.decode('gbk'))
View Code