0. 基础

将.ui 转化为.py

  • python -m PyQt5.uic.pyuic demo.ui -o demo.py

读取期望尺寸

  • 期望尺寸

    self.pushButton.sizeHint().width()

  • 最小期望尺寸

    self.pushButton.minimumSizeHint().width()

主窗口类型

  • QMainWindow:可以包含菜单栏、工具栏、状态栏和标题栏,是最常见的窗口形式
  • QDialog:是对话窗口的基类。没有菜单栏、工具栏、状态栏。
  • QWidget:不确定窗口的用途,就使用 QWidget。

初始代码

  • ```python
    import sys
    from PyQt5.QtWidgets import QHBoxLayout,QMainWindow,QApplication,QPushButton,QWidget

    class QuitApplication(QMainWindow):

    def __init__(self):
        super(QuitApplication,self).__init__()
        self.resize(300,120)
        self.setWindowTitle('退出应用程序')
    
        # 添加Button
    
        self.button1 = QPushButton('退出应用程序')
        # 将信号与槽关联
        self.button1.clicked.connect(self.onClick_Button)
    
        layout = QHBoxLayout()
        layout.addWidget(self.button1)
    
        mainFrame = QWidget()
        mainFrame.setLayout(layout)
    
        self.setCentralWidget(mainFrame)
    
    # 按钮单击事件的方法(自定义的槽)
    def onClick_Button(self):
        sender = self.sender()
        print(sender.text() + ' 按钮被按下')
        app = QApplication.instance()
        # 退出应用程序
        app.quit()
    

    if name == ‘main‘:

    app = QApplication(sys.argv)
    main = QuitApplication()
    main.show()
    sys.exit(app.exec_())
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    ## 窗口尺寸

    - `widget.size(300, 240) # 设置工作区尺寸`

    - ```python
    print("1")
    print("widget.x() = %d" % widget.x())
    print("widget.y() = %d" % widget.y()) # 不含标题栏
    print("widget.width() = %d" % widget.width())
    print("widget.height() = %d" % widget.height())

    print("2")
    print("widget.geometry().x() = %d" % widget.geometry().x())
    print("widget.geometry().y() = %d" % widget.geometry().y()) # 含标题栏
    print("widget.geometry().width() = %d" % widget.geometry().width())
    print("widget.geometry().height() = %d" % widget.geometry().height())

    print("3")
    print("widget.frameGeometry().x() = %d" % widget.frameGeometry().x())
    print("widget.frameGeometry().y() = %d" % widget.frameGeometry().y())
    print("widget.frameGeometry().width() = %d" % widget.frameGeometry().width())
    print("widget.frameGeometry().height() = %d" % widget.frameGeometry().height()) # 含标题栏

设置提示消息

  • self.button.setToolTip('提示内容')

QLabel 控件

setAlignment():设置文本的对齐方式

setColor():设置背景色

setIndent():设置文本缩进

text():获取文本内容

setBuddy():设置伙伴关系

当用户激活标签的 快捷键 时,鼠标/键盘的焦点将会转移到它的 伙伴 窗口部件上。 QT 对象中只有 QLabel 标签对象才可以有 伙伴 窗口部件,也只有 QLabel 对象具有 快捷键 时, 伙伴 关系才有效。

setText():设置文本内容

selectedText():返回所选择的字符

setWordWrap():设置是否允许换行

QLabel 常用的信号(事件):

  1. 当鼠标滑过 QLabel 控件时触发:linkHovered
  2. 当鼠标单击 QLabel 控件时触发:linkActivated
    • setOpenExternalLinks(True):网址打开,与事件互斥

QLineEdit 与回显模式

QLineEdit 控件与回显模式

基本功能:输入单行的文本

EchoMode(回显模式)

4 种回显模式

  1. Normal
  2. NoEcho
  3. Password
  4. PasswordEchoOnEdit

QLineEdit().setValidator()文本检验器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 创建表单布局
formLayout = QFormLayout()

intLineEdit = QLineEdit()
doubleLineEdit = QLineEdit()
validatorLineEdit = QLineEdit()

formLayout.addRow('整数类型', intLineEdit)
formLayout.addRow('浮点类型', doubleLineEdit)
formLayout.addRow('数字和字母', validatorLineEdit)

# 设置校验器
# QIntValidator 整数校验器
intValidator = QIntValidator(self)
intValidator.setRange(1, 99)

# QDoubleValidator 浮点数校验器
# 参数1: 小数点前的位数
# 参数2: 小数点后的位数
# 参数3: 浮点数的精度
doubleValidator = QDoubleValidator(self)
doubleValidator.setRange(-360, 360)
doubleValidator.setNotation(QDoubleValidator.StandardNotation)
doubleValidator.setDecimals(2)

# QRegExpValidator 正则表达式校验器
reg = QRegExp('[a-zA-Z0-9]+$')
regValidator = QRegExpValidator(self)
regValidator.setRegExp(reg)

# 设置校验器
intLineEdit.setValidator(intValidator)
doubleLineEdit.setValidator(doubleValidator)
validatorLineEdit.setValidator(regValidator)

QLineEdit 掩码限制

用掩码限制 QLineEdit 控件的输入

  • A ASCII 字母字符是必须输入的(A-Z、a-z)
  • a ASCII 字母字符是允许输入的,但不是必需的(A-Z、a-z)
  • N ASCII 字母字符是必须输入的(A-Z、a-z、0-9)
  • n ASII 字母字符是允许输入的,但不是必需的(A-Z、a-z、0-9)
  • X 任何字符都是必须输入的
  • x 任何字符都是允许输入的,但不是必需的
  • 9 ASCII 数字字符是必须输入的(0-9)
  • 0 ASCII 数字字符是允许输入的,但不是必需的(0-9)
  • D ASCII 数字字符是必须输入的(1-9)
  • d ASCII 数字字符是允许输入的,但不是必需的(1-9)
  • # ASCI 数字字符或加减符号是允许输入的,但不是必需的
  • H 十六进制格式字符是必须输入的(A-F、a-f、0-9)
  • h 十六进制格式字符是允许输入的,但不是必需的(A-F、a-f、0-9)
  • B 二进制格式字符是必须输入的(0,1)
  • b 二进制格式字符是允许输入的,但不是必需的(0,1)
  • > 所有的字母字符都大写
  • < 所有的字母字符都小写
  • ! 关闭大小写转换
  • \ 使用”\”转义上面列出的字符
1
2
3
4
5
# 192.168.21.45
ipLineEdit.setInputMask('000.000.000.000;_')
macLineEdit.setInputMask('HH:HH:HH:HH:HH:HH;_')
dateLineEdit.setInputMask('0000-00-00')
licenseLineEdit.setInputMask('>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#')

1. 串口操作

1
2
3
4
5
6
7
8
9
10
11
12
13
import serial	# 引入 serial 库

port_list = list(serial.tools.list_ports.comports()) # 搜索串口列表

ser = serial.Serial(com, int(bps), timeout=int(timex))

ser.flushInput() # 清空缓冲区

count = ser.inWaiting() # 获取缓冲区字符数量

str = ser.readline(ser.in_waiting) # 读取内容并回显

str = glo.ser.read(ser.in_waiting)

1.1 搜索串口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class getCom(QThread):
comUpdate = pyqtSignal(list)
port_list_orignal = []

def run(self):
"""得到所有的串口号
args: NONE
return: (串口号列表: ['COM1', ...], 串口名列表: ['通信端口 (COM1)'], 串口列表: ['COM1 - 通信端口 (COM1)', ...])
"""
while(True):
port_list = list(serial.tools.list_ports.comports())
if set(port_list) != set(self.port_list_orignal):
self.port_listUpdate(port_list)
if len(port_list) == 0:
print('No serial port found!')
exit()
else:
self.comUpdate.emit(port_list)

def port_listUpdate(self, port_list):
self.port_list_orignal = port_list

1.2 打开串口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def serialOpen(com, bps, timex):
"""打开串口
args: com: 串口号; bps: 波特率; timex: 超时时间
return: ser: 串口对象
"""
try:
ser = serial.Serial(com, int(bps), timeout=int(timex))
if ser.isOpen():
print('open success')
return ser
else:
print('open failed')
return None
except:
print("serialOpen: 串口不存在")
return
finally:
...

1.3 串口数据读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class serialRead_original(QThread):
dateReadUpdate = pyqtSignal(str) # 数据更新信号
serDisconnect = pyqtSignal() # 串口断开信号

def run(self):
"""读取串口数据
args: NONE
return: NONE
"""
print("serialRead start")
ser.flushInput() # 清空缓冲区
while(isConnected):
if serialIsOpen(ser) == False: # 串口断开 或 不存在
print("serialRead stop")
self.serDisconnect.emit()
serialClose(ser)
break
count = ser.inWaiting() # 获取缓冲区字符数量
# print("count: ", count)
if count != 0:
str = ser.readline(ser.in_waiting) # 读取内容并回显
# str = glo.ser.read(ser.in_waiting)
# str -> b'' => 二进制数据
# str = str.decode(encoding='utf-8', errors='ignore')
self.dateReadUpdate.emit(str)
# print('data:', data)
sleep(1)

2. QChartView

image-20230320092601751

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class chartView(QFrame):
def __init__(self):
self.ChartView = QChartView() # 图表视图(需要从QGraphicsView提升)
self.initChart()

def initChart(self):
self.chart = QChart() # 图表
self.dataAxisX = QValueAxis() # X轴数据
self.dataAxisY = QValueAxis() # Y轴数据
self.series = qSplineSeries() # 数据序列
self.chart.addSeries(self.series) # 数据序列 与 图表匹配
self.chart.addAxis(self.dataAxisX, Qt.AlignBottom) # X轴配对
self.chart.addAxis(self.valueAxisY, Qt.AlignLeft) # Y轴配对

class mainWin(QWeight):
def __init__(self):
self.chartView = chartView()
...

def addData(self):
self.series.add(x_point, y_point) # 只能逐点添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from PyQt5.QtWidgets import QFrame, QHBoxLayout, QCheckBox
from PyQt5.QtChart import QChartView, QChart, QSplineSeries, QValueAxis
from PyQt5.QtCore import Qt, QMargins
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import QPointF
import sys


class chartFrame(QFrame):
def __init__(self):
super().__init__()
self.setupUi()
self.initChart()
self.ChartView.setChart(self.chart)
self.setLayout(self.horizontalLayout)
self.ChartView.setRenderHint(QPainter.Antialiasing) # 抗锯齿
self.ChartView.setRubberBand(QChartView.RectangleRubberBand) # 可框选

def setupUi(self):
self.horizontalLayout = QHBoxLayout()
self.checkBox = QCheckBox()
self.checkBox.setText("")
self.checkBox.setChecked(True)
self.checkBox.stateChanged.connect(self.checkBoxClicked)
self.ChartView = QChartView()
self.horizontalLayout.addWidget(self.checkBox)
self.horizontalLayout.addWidget(self.ChartView)

def initChart(self):
self.chart = QChart()
self.chart.setMargins(QMargins(0, 0, 0, 0))
self.chart.setBackgroundRoundness(0) # 设置背景圆角

self.series = QSplineSeries()
# self.series.useOpenGL() # 使用OpenGL加速
self.chart.addSeries(self.series)

self.dataAxisX = QValueAxis()
self.dataAxisX.setMax(0)
self.dataAxisX.setTickCount(6)
self.dataAxisX.setMinorTickCount(3)
self.dataAxisX.setRange(0, 1)

self.valueAxisY = QValueAxis()
self.valueRange = 200000
self.valueAxisY.setRange(-(self.valueRange * 1.1),
self.valueRange * 1.1)
self.valueAxisY.setLabelFormat('%.1f')
self.valueAxisY.setTickCount(6)
self.valueAxisY.setMinorTickCount(2)
self.valueAxisY.setVisible(False)

self.chart.addAxis(self.dataAxisX, Qt.AlignBottom)
self.chart.addAxis(self.valueAxisY, Qt.AlignLeft)
self.chart.legend().hide()
# self.chart.setAnimationOptions(QChart.SeriesAnimations) # 设置动画:chart中启用了所有动画类型
self.chart.setAnimationOptions(QChart.NoAnimation) # 设置动画:chart中不启用动画
# self.chart.createDefaultAxes() # 创建默认轴 可用在加载数据时使用

self.series.attachAxis(self.dataAxisX)
self.series.attachAxis(self.valueAxisY)

def checkBoxClicked(self):
if self.checkBox.isChecked() == False:
self.setVisible(False)
self.checkBox.setChecked(True)

def keyPressEvent(self, e) -> None:
if e.key() == Qt.Key_Enter:
self.chart.zoomReset()

if __name__ == '__main__':
app = QApplication(sys.argv)
w = chartFrame()
w.show()
sys.exit(app.exec_())

3. Matplotlib 图表集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import sys

import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from scipy.signal import butter, filtfilt

from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QLineEdit, QPushButton, QComboBox, QFrame, QCheckBox
from PyQt5.QtCore import Qt, QTimer, QCoreApplication

import numpy as np
import time
import random


class MyMplCanvas(FigureCanvas):
"""A canvas that updates itself every second with a new plot."""

def __init__(self):
global xdata, ydata
self.fig, self.ax = plt.subplots()
ymax = 200000
self.ax.set_ylim(-ymax, ymax)
self.ax.set_xlim(0, 2000)
self.ax.set_axis_off()
self.line, = self.ax.plot([], [])
FigureCanvas.__init__(self, self.fig)

# 每隔 1ms 更新图表
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_figure)
self.timer.start(1) # 更新时间间隔为1ms

def update_figure(self):
# if glo.connected:
self.draw()
# print(time.time())
...

class chartFrame(QFrame):
def __init__(self):
super().__init__()
self.initUI()

def initUI(self):
global xdata, ydata

self.Hlayout = QHBoxLayout()
self.checkBox = QCheckBox()
self.checkBox.setText("")
self.checkBox.setChecked(True)
self.checkBox.stateChanged.connect(self.checkBoxClicked)

self.canvasFrame = QFrame()
self.canvasFrame.setFrameShape(QFrame.StyledPanel)
self.canvas = MyMplCanvas()
xdata = np.arange(0, 2000, 1)
ydata = np.zeros(2000)
self.canvas.line.set_data(xdata, ydata)

self.Hlayout.addWidget(self.checkBox)
self.canvasLayout = QVBoxLayout()
self.canvasLayout.addWidget(self.canvas)
self.canvasFrame.setLayout(self.canvasLayout)
self.Hlayout.addWidget(self.canvasFrame)
self.setLayout(self.Hlayout)


def checkBoxClicked(self):
if self.checkBox.isChecked() == False:
self.setVisible(False)
self.checkBox.setChecked(True)

def addData(self, data):
global xdata, ydata
len_data = len(data)
ydata[:-len_data] = ydata[len_data:]
ydata[-len_data:] = data

self.canvas.line.set_data(xdata, ydata)

def keyPressEvent(self, e) -> None:
if e.key() == Qt.Key_Enter:
self.chart.zoomReset()


if __name__ == '__main__':
global xdata, ydata
glo.__init__()
app = QApplication(sys.argv)
w = chartFrame()
w.show()
app.exec_()

4. 正则表达式 re

4.1 re 库

4.1.1 re.match

re.match(pattern, string, flags=0)

尝试从字符串的起始位置匹配一个模式。匹配成功 re.match 方法返回一个匹配的对象。没有匹配成功的,re.search()返回 None。

group()用来提出分组截获的字符串()用来分组,group() 同 group(0)就是匹配正则表达式整体结果,group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分。

1
2
3
4
>>> import re
>>> result = re.match("itcast","itcast.cn")
>>> result.group()
'itcast'
arg 说明
pattern 匹配的正则表达式
string 要匹配的字符串
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

1. re.I 忽略大小写
2. re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
3. re.M 多行模式
4. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
5. re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
6. re.X 为了增加可读性,忽略空格和 # 后面的注释

4.1.2 re.compile

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。

1
2
3
4
prog = re.compile(pattern)
result = prog.match(string)
# 等价于
result = re.match(pattern, string)
  • group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
  • start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
  • end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
  • span([group]) 方法返回 (start(group), end(group))

re.search 扫描整个字符串并返回第一个成功的匹配,如果没有匹配,就返回一个 None。

re.match 与 re.search 的区别:re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None;而 re.search 匹配整个字符串,直到找到一个匹配

1
2
3
4
5
import re
ret = re.search(r"\d+", "阅读次数为9999")
print(ret.group())

>>> 9999

4.1.4 re.findall

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。注意: match 和 search 是匹配一次 findall 匹配所有。

举例:

1
2
3
4
5
import re
ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
print(ret)

>>> ['9999', '7890', '12345']

4.1.5 re.finditer

和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

1
2
3
4
5
6
7
8
9
10
import re
it = re.finditer(r"\d+", "12a32bc43jf3")
for match in it:
print(match.group())

>>>
12
32
43
3

4.1.6 re.sub

sub 是 substitute 的所写,表示替换,将匹配到的数据进⾏替换。

1
2
3
4
5
import re
ret = re.sub(r"\d+", '998', "python = 997")
print(ret)

>>> python = 998

re.sub(pattern, repl, string, count=0, flags=0)

参数 描述
pattern 必选,表示正则中的模式字符串
repl 必选,就是 replacement,要替换的字符串,也可为一个函数
string 必选,被替换的那个 string 字符串
count 可选参数,count 是要替换的最大次数,必须是非负整数。如果省略这个参数或设为 0,所有的匹配都会被替换
flag 可选参数,标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

4.1.7 re.subn

行为与sub()相同,但是返回一个元组 (字符串, 替换次数)

1
2
3
4
5
6
7
8
9
10
11
import re
pattern = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print(re.subn(pattern, r'\2 \1', s))
def func(m):
return m.group(1).title() + ' ' + m.group(2).title()
print(re.subn(pattern, func, s))

>>>
('say i, world hello!', 2)
('I Say, Hello World!', 2)

re.subn(pattern, repl, string[, count])

return: (sub(repl, string[, count]), 替换次数)

4.1.8 re.split

根据匹配进⾏切割字符串,并返回⼀个列表。

1
2
3
4
5
import re
ret = re.split(r":| ","info:xiaoZhang 33 shandong")
print(ret)

>>> ['info', 'xiaoZhang', '33', 'shandong']

re.split(pattern, string, maxsplit=0, flags=0)

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串
maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数

4.1.9 r’’

字符串前⾯加上 r 表示原⽣字符串

1
2
3
4
5
import re
mm = "c:\\a\\b\\c"

ret = re.match(r"c:\\a",mm).group()
print(ret)#c:\a

4.2 正则表达式基础知识

普通字符

字符 描述
[ABC] 匹配 […] 中的所有字符,例如 [aeiou] 匹配字符串 “google runoob taobao” 中所有的 e o u a 字母。img
ABC 匹配除了 […] 中字符的所有字符,例如 aeiou 匹配字符串 “google runoob taobao” 中除了 e o u a 字母的所有字母。img
[A-Z] [A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母。img
. 匹配除换行符(\n、\r)之外的任何单个字符,相等于 \n\rimg
[\s\S] 匹配所有。\s 是匹配所有空白符,包括换行,\S 非空白符,不包括换行。img
\w 匹配字母、数字、下划线。等价于 [A-Za-z0-9_]img
\w 匹配⾮单词字符
\d 匹配数字,即 0-9
\D 匹配⾮数字,即不是数字

非打印字符

字符 描述
\cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S 匹配任何非空白字符。等价于 \f\n\r\t\v
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

特殊字符

特别字符 描述
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 $。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 ( 和 )。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 *。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。
. 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 . 。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 [。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\‘ 匹配 “\”,而 ‘(‘ 则匹配 “(“。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 \^。
{ 标记限定符表达式的开始。要匹配 {,请使用 {。
\ 指明两项之间的一个选择。要匹配 \ ,请使用 \

限定符

字符 描述
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”* 等价于 {0,}
+ 匹配前面的子表达式一次或多次。例如,zo+ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”+ 等价于 {1,}
? 匹配前面的子表达式零次或一次。例如,do(es)? 可以匹配 “do”“does”“doxy” 中的 “do”“does”? 等价于 {0,1}img
{n} n 是一个非负整数。匹配确定的 n 次。例如,o{2} 不能匹配 “Bob” 中的 o,但是能匹配 “food” 中的两个 o
{n,} n 是一个非负整数。至少匹配 n 次。例如,o{2,} 不能匹配 “Bob” 中的 o,但能匹配 “foooood” 中的所有 oo{1,} 等价于 o+o{0,} 则等价于 o*
{n,m} m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。例如,o{1,3} 将匹配 “fooooood” 中的前三个 oo{0,1} 等价于 o?。请注意在逗号和两个数之间不能有空格。

定位符

字符 描述
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
\b 匹配一个单词边界,即字与空格间的位置。
\B 非单词边界匹配。

4.3 贪婪与非贪婪

属于贪婪模式的量词,也叫做匹配优先量词,包括:

“{m,n}”、“{m,}”、“?”、“*”和“+”。

在一些使用 NFA 引擎的语言中,在匹配优先量词后加上“?”,即变成属于非贪婪模式的量词,也叫做忽略优先量词,包括:

“{m,n}?”、“{m,}?”、“??”、“*?”和“+?”。

5.QTextEdit

1
2
3
4
5
self.et_print.textCursor().insertText("hello")	# 光标处添加文字

self.textEdit.append('hello') # 添加文字到新行

self.showLogText.moveCursor(QTextCursor.End) # 光标移动到行尾

6. PyQt6

6.1 枚举

  • 最可能影响项目的更改是删除枚举成员的缩写名称,在 pyqt6 中,所有枚举和标志必须要使用他全限定命名,包括那些在 QtCore.Qt 命名空间。例如,PyQt6 中的 Qt.Checked 标志变为 Qt.CheckState.Checked。
1
2
3
4
5
6
7
# pyqt5
widget = QCheckBox("This is a checkbox")
widget.setCheckState(Qt.Checked)

# pyqt6
widget = QCheckBox("This is a checkbox")
widget.setCheckState(Qt.CheckState.Checked)

6.2 exec()

  • 使用 .exec() 代替 .exec_()

6.3 可以使用 pyinstaller