Skip to content

Commit 390bcf0

Browse files
authored
Merge pull request #1 from user0706/feature/test-string-highlighting
2 parents 4e306d8 + d423041 commit 390bcf0

File tree

8 files changed

+312
-122
lines changed

8 files changed

+312
-122
lines changed

Example.png

-3.51 KB
Loading
File renamed without changes.
File renamed without changes.
File renamed without changes.

README.md

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,40 @@
22
<img height="100" src="https://github.com/user0706/PyRex/blob/master/icons/windowIcon.png?raw=true">
33
</p>
44

5-
# About PyRex
6-
PyRex is a tool for testing python regular expression.
7-
<br>Workspace can be grouped into three areas: pattern, test string and match information area.
5+
[![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/) [![python-version](https://img.shields.io/badge/Python-3.6|3.7-<COLOR>.svg)](https://www.python.org/) [![Qt](https://img.shields.io/badge/GUI%20by-Qt%20Designer-orange)](https://doc.qt.io/qt-5/qtdesigner-manual.html) [![PyPI license](https://img.shields.io/pypi/l/ansicolortags.svg)](https://pypi.python.org/pypi/ansicolortags/) [![PyPI status](https://img.shields.io/pypi/status/ansicolortags.svg)](https://pypi.python.org/pypi/ansicolortags/)
6+
## Description
7+
PyRex is a tool for visual testing Python regular expression.
8+
<br>Based on the re python package, combined with the Qt user interface, it allows a visual display of the results of a regular expression pattern.
9+
10+
:warning: **This is a beta version and probably contains some bugs. In that case, please [report the new issue](https://github.com/user0706/PyRex/issues).**
11+
12+
## Prerequisites
13+
After opening the downloaded repository in cmd *(Windows)*/terminal *(Linux/MacOS)*, to install the necessary packages for PyRex operation, enter the following command:
14+
```python
15+
pip install -r requirements.txt --no-index --find-links file:///tmp/packages
16+
```
17+
## How to run PyRex?
18+
Execute the following commands in cmd *(Windows)*/terminal *(Linux/MacOS)*:
19+
20+
- Download repository
21+
```
22+
git clone https://github.com/user0706/PyRex.git
23+
```
24+
- Entry into the download repository
25+
```
26+
cd PyRex
27+
```
28+
- Start the program
29+
```
30+
python main.py
31+
(if not, try python3)
32+
```
33+
34+
## What's new:
35+
- Test_string highlighting features
836

937
## Screenshots
10-
![](https://github.com/user0706/PyRex/blob/master/Example.png?raw=true)
38+
![](https://github.com/user0706/PyRex/blob/feature/test-string-highlighting/Example.png?raw=true)
1139

1240
## To-Do
1341
- [ ] Fill groups in real-time in pattern areas

functions.py

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
from mainGUI import *
2+
from PyQt5.QtGui import *
3+
from PyQt5.QtWidgets import *
4+
from PyQt5.QtCore import *
5+
import sys
6+
7+
import re
8+
import random
9+
10+
def Process(string, pattern, info):
11+
'''Processes the specified regex pattern
12+
13+
:param pattern: Regex pattern
14+
:type pattern: str
15+
:param string: Test string
16+
:type string: str
17+
:returns info: Search result information
18+
:type info: list
19+
20+
:Example: string => "HELLO world
21+
Great day"
22+
pattern => [A-Z]+.*
23+
info => []
24+
25+
return info => [["Full match 1", "[0-10]", "HELLO world"]]
26+
'''
27+
if pattern:
28+
try:
29+
regex = r"{}".format(str(pattern))
30+
matches = re.finditer(regex, string, re.MULTILINE)
31+
for match_num, match in enumerate(matches, start=1):
32+
info.append(['Full match '+str(match_num), str(match.start())+'-'+str(match.end()), str(match.group())])
33+
for group_num in range(0, len(match.groups())):
34+
group_num = group_num + 1
35+
info.append(['Group '+str(group_num), str(match.start(group_num))+'-'+str(match.end(group_num)), str(match.group(group_num))])
36+
except:
37+
pass
38+
return info
39+
40+
def GenerateGroupColor(color_spectrum, target):
41+
'''Color generator for groups
42+
43+
:param target: Result info group name
44+
:type target: str
45+
:param color_spectrum: List of optional colors
46+
:type color_spectrum: list
47+
:returns: Selected rgb color
48+
:type: str
49+
'''
50+
if target == 'Group 1':
51+
color = color_spectrum[1]
52+
elif target == 'Group 2':
53+
color = color_spectrum[2]
54+
elif target == 'Group 3':
55+
color = color_spectrum[3]
56+
elif target == 'Group 4':
57+
color = color_spectrum[4]
58+
elif target == 'Group 5':
59+
color = color_spectrum[5]
60+
elif target == 'Group 6':
61+
color = color_spectrum[6]
62+
elif target == 'Group 7':
63+
color = color_spectrum[7]
64+
elif target == 'Group 8':
65+
color = color_spectrum[8]
66+
elif target == 'Group 9':
67+
color = color_spectrum[9]
68+
elif target == 'Group 10':
69+
color = color_spectrum[10]
70+
else:
71+
color = random.choice(color_spectrum)
72+
return color
73+
74+
def FullMatchTagUI(scroll_area, layout, tag):
75+
'''Full match tag header - The dynamic part of Qt ui
76+
77+
:param scroll_area: QT ui scroll area
78+
:type: PyQt5.QtWidgets.QScrollArea
79+
:param layout: QT ui scroll area layout
80+
:type: PyQt5.QtWidgets.QHBoxLayout
81+
'''
82+
CollectionWidget = QtWidgets.QWidget(scroll_area)
83+
CollectionWidget.setMinimumSize(QtCore.QSize(300, 25))
84+
CollectionWidget.setMaximumSize(QtCore.QSize(500, 25))
85+
CollectionWidget.setObjectName("CollectionWidget")
86+
verticalLayout_6 = QtWidgets.QVBoxLayout(CollectionWidget)
87+
verticalLayout_6.setContentsMargins(0, 0, 0, 0)
88+
verticalLayout_6.setSpacing(0)
89+
verticalLayout_6.setObjectName("verticalLayout_6")
90+
CollectionLabel = QtWidgets.QLabel("Match {}".format(str(tag.split(' ')[-1])))
91+
font = QtGui.QFont()
92+
font.setPointSize(8)
93+
font.setBold(True)
94+
CollectionLabel.setFont(font)
95+
CollectionLabel.setStyleSheet("color: rgb(78, 123, 179);\nmargin-bottom:5px;\nmargin-top:10px;")
96+
CollectionLabel.setObjectName("CollectionLabel")
97+
verticalLayout_6.addWidget(CollectionLabel)
98+
CollectionLine = QtWidgets.QFrame(CollectionWidget)
99+
CollectionLine.setStyleSheet("background-color: rgba(199, 199, 199, 50%);\nmin-height:1px;\nmax-height:1px;")
100+
CollectionLine.setFrameShape(QtWidgets.QFrame.HLine)
101+
CollectionLine.setFrameShadow(QtWidgets.QFrame.Sunken)
102+
CollectionLine.setObjectName("CollectionLine")
103+
verticalLayout_6.addWidget(CollectionLine)
104+
layout.addWidget(CollectionWidget)
105+
106+
def InfoUI(res_widget, res_layout, res_tag, res_range, res_text, res_index, res_color, scroll_area, layout, tag):
107+
'''UI information widget element - The dynamic part of Qt ui
108+
109+
:param res_widget: A list where the i-th element is the i-th Qt widget
110+
:type res_widget: list
111+
:param res_layout: A list where the i-th element is the i-th Qt H layout
112+
:type res_layout: list
113+
:param res_tag: A list where the i-th element is the i-th tag
114+
:type res_tag: list
115+
:param res_range: A list where the i-th element is the i-th range
116+
:type res_range: list
117+
:param res_text: A list where the i-th element is the i-th text
118+
:type res_text: list
119+
:param res_index: Current element-widget
120+
:type res_index: int
121+
:param res_color: Tag background color
122+
:type res_color: str
123+
:param scroll_area: Qt ui scroll area
124+
:type scroll_area: PyQt5.QtWidgets.QScrollArea
125+
:param layout: Qt ui scroll area layout
126+
:type layout: PyQt5.QtWidgets.QHBoxLayout
127+
:param tag: Tag name
128+
:type tag: str
129+
'''
130+
res_widget[res_index] = QtWidgets.QWidget(scroll_area)
131+
res_widget[res_index].setObjectName("ResultWidget")
132+
res_layout[res_index] = QtWidgets.QHBoxLayout(res_widget[res_index])
133+
res_layout[res_index].setContentsMargins(0, 7, 0, 0)
134+
res_layout[res_index].setObjectName("horizontalLayout_4")
135+
if 'Full match' in tag[0]:
136+
res_tag[res_index] = QtWidgets.QLabel(' '.join(tag[0].split(' ')[:-1]))
137+
else:
138+
res_tag[res_index] = QtWidgets.QLabel(tag[0])
139+
res_tag[res_index].setStyleSheet("min-width:60px;\nmax-width:60px;\nmin-height:20px;\nmax-height:20px;\nbackground-color: {};\nborder:2px;\nborder-radius:3px;\ncolor: rgb(54, 54, 54);\n".format(res_color))
140+
res_tag[res_index].setAlignment(QtCore.Qt.AlignCenter)
141+
res_tag[res_index].setObjectName("ResultTag")
142+
res_layout[res_index].addWidget(res_tag[res_index], 0, QtCore.Qt.AlignTop)
143+
res_range[res_index] = QtWidgets.QLabel(tag[1])
144+
res_range[res_index].setStyleSheet("min-width:60px;\nmax-width:60px;\nmin-height:20px;\nmax-height:20px;\ncolor: rgb(54, 54, 54);\n")
145+
res_range[res_index].setAlignment(QtCore.Qt.AlignCenter)
146+
res_range[res_index].setWordWrap(True)
147+
res_range[res_index].setObjectName("ResultRange")
148+
res_layout[res_index].addWidget(res_range[res_index], 0, QtCore.Qt.AlignTop)
149+
res_text[res_index] = QtWidgets.QLabel(tag[2])
150+
res_text[res_index].setStyleSheet("min-width:200px;\nmin-height:20px;\npadding-left:5px;\nbackground-color: rgba(98, 98, 98, 10%);\nborder:2px;\nborder-radius:3px;\ncolor: rgb(54, 54, 54);\n")
151+
res_text[res_index].setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
152+
res_text[res_index].setWordWrap(True)
153+
res_text[res_index].setObjectName("ResultText")
154+
res_layout[res_index].addWidget(res_text[res_index], 0, QtCore.Qt.AlignTop)
155+
layout.addWidget(res_widget[res_index])
156+
157+
def PreprocessInfo(info):
158+
'''Define the length of the list of variables for those used in UpdateInfo
159+
160+
:return res_widget: list with the same length as info parameter
161+
:rtype res_widget: list
162+
:return res_layout: list with the same length as info parameter
163+
:rtype res_layout: list
164+
:return res_tag: list with the same length as info parameter
165+
:rtype res_tag: list
166+
:return res_range: list with the same length as info parameter
167+
:rtype res_range: list
168+
:return res_text: list with the same length as info parameter
169+
:rtype res_text: list
170+
'''
171+
res_widget = list(range(len(info)))
172+
res_layout = list(range(len(info)))
173+
res_tag = list(range(len(info)))
174+
res_range = list(range(len(info)))
175+
res_text = list(range(len(info)))
176+
return res_widget, res_layout, res_tag, res_range, res_text
177+
178+
def clearLayout(layout):
179+
'''Cleaning the previous state of Layout
180+
181+
:param layout: Layout to be cleaned
182+
:type layout: PyQt5.QtWidgets.QHBoxLayout
183+
'''
184+
while layout.count():
185+
child = layout.takeAt(0)
186+
if child.widget():
187+
child.widget().deleteLater()
188+
189+
def Highlight(plain_edit, color, start, end):
190+
'''Highlights/marks the appropriate substring of the test string
191+
192+
:param plain_edit: Plain edit component. NOT text from plain edit
193+
:type plain_edit: PyQt5.QtWidgets.QPlainTextEdit
194+
:param color: Matching color for the background of the corresponding group - tag result
195+
:type color: str
196+
:param start: Starting position/index of substring for marking.
197+
:type start: int
198+
:param end: Ending position/index of substring for marking.
199+
:type end: int
200+
'''
201+
fmt = QTextCharFormat()
202+
fmt.setBackground(color)
203+
cursor = QTextCursor(plain_edit.document())
204+
cursor.setPosition(start, QTextCursor.MoveAnchor)
205+
cursor.setPosition(end, QTextCursor.KeepAnchor)
206+
cursor.setCharFormat(fmt)
207+
208+
def ClearHighlight(plain_edit, plain_edit_text):
209+
'''Reset all highlighted/marked substrings from the test string
210+
211+
:param plain_edit: Plain edit component. NOT text from plain edit
212+
:type plain_edit: PyQt5.QtWidgets.QPlainTextEdit
213+
:param plain_edit_text: Text from plaind edit
214+
:type plain_edit_text: str
215+
'''
216+
fmt = QTextCharFormat()
217+
fmt.setBackground(QColor(Qt.white))
218+
cursor = QTextCursor(plain_edit.document())
219+
cursor.setPosition(0, QTextCursor.MoveAnchor)
220+
cursor.setPosition(len(list(plain_edit_text)), QTextCursor.KeepAnchor)
221+
cursor.setCharFormat(fmt)
222+
223+
def HighlightRange(string):
224+
'''Convert a range from a string type to a list of integers
225+
226+
:param string: The range of substring to be highlighted
227+
:type string: str
228+
:return : The range of substring to be highlighted
229+
:rtype : list
230+
231+
:Example: string => "[2-9]"
232+
return => [2,9]
233+
'''
234+
return [int(re.sub(r'(\[|\])','',i)) for i in string.split('-')]
235+
236+
def strColorTolist(string):
237+
'''Convert string type rgb colors to separate integer values of red - green - blue
238+
239+
:param string: Rgb color as a string
240+
:type string: str
241+
:return colorList[0]: Red value
242+
:rtype colorList[0]: int
243+
:return colorList[1]: Green value
244+
:rtype colorList[1]: int
245+
:return colorList[2]: Blue value
246+
:rtype colorList[2]: int
247+
248+
:Example: string => "rgb(255,100,50)"
249+
return colorList[0] => 255
250+
return colorList[1] => 100
251+
return colorList[2] => 50
252+
'''
253+
colorList = [int(i) for i in re.sub(r'(rgb\(|\))','',string).split(', ')]
254+
return colorList[0],colorList[1],colorList[2]

0 commit comments

Comments
 (0)