Skip to content

Commit 7008364

Browse files
authored
Merge pull request #3347 from PyWoody/highlight_regex_compiled
highlight_regex in rich.text.Text Now Expects a Compiled Regular Expression (re.compile) Has Been Passed
2 parents 68ead31 + b5d063c commit 7008364

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5555
- Running tests in environment with `FORCE_COLOR` or `NO_COLOR` environment variables
5656
- ansi decoder will now strip problematic private escape sequences (like `\x1b7`) https://github.com/Textualize/rich/pull/3278/
5757
- Tree's ASCII_GUIDES and TREE_GUIDES constants promoted to class attributes
58+
- `rich.Text.highlight_regex` now accepts a regular expression object https://github.com/Textualize/rich/pull/3347
5859

5960
### Added
6061

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ The following people have contributed to the development of Rich:
8787
- [Pierro](https://github.com/xpierroz)
8888
- [Bernhard Wagner](https://github.com/bwagner)
8989
- [Aaron Beaudoin](https://github.com/AaronBeaudoin)
90+
- [Sam Woodward](https://github.com/PyWoody)
9091
- [L. Yeung](https://github.com/lewis-yeung)
9192
- [chthollyphile](https://github.com/chthollyphile)
9293
- [Jonathan Helmus](https://github.com/jjhelmus)

rich/text.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ def extend_style(self, spaces: int) -> None:
591591

592592
def highlight_regex(
593593
self,
594-
re_highlight: str,
594+
re_highlight: Union[re.Pattern, str],
595595
style: Optional[Union[GetStyleCallable, StyleType]] = None,
596596
*,
597597
style_prefix: str = "",
@@ -600,7 +600,7 @@ def highlight_regex(
600600
translated to styles.
601601
602602
Args:
603-
re_highlight (str): A regular expression.
603+
re_highlight (Union[re.Pattern, str]): A regular expression object or string.
604604
style (Union[GetStyleCallable, StyleType]): Optional style to apply to whole match, or a callable
605605
which accepts the matched text and returns a style. Defaults to None.
606606
style_prefix (str, optional): Optional prefix to add to style group names.
@@ -612,7 +612,9 @@ def highlight_regex(
612612
append_span = self._spans.append
613613
_Span = Span
614614
plain = self.plain
615-
for match in re.finditer(re_highlight, plain):
615+
if isinstance(re_highlight, str):
616+
re_highlight = re.compile(re_highlight)
617+
for match in re_highlight.finditer(plain):
616618
get_span = match.span
617619
if style:
618620
start, end = get_span()

tests/test_text.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from io import StringIO
23
from typing import List
34

@@ -159,6 +160,7 @@ def test_stylize_negative_index():
159160

160161

161162
def test_highlight_regex():
163+
# As a string
162164
text = Text("peek-a-boo")
163165

164166
count = text.highlight_regex(r"NEVER_MATCH", "red")
@@ -176,6 +178,7 @@ def test_highlight_regex():
176178
]
177179

178180
text = Text("Ada Lovelace, Alan Turing")
181+
179182
count = text.highlight_regex(
180183
r"(?P<yellow>[A-Za-z]+)[ ]+(?P<red>[A-Za-z]+)(?P<NEVER_MATCH>NEVER_MATCH)*"
181184
)
@@ -189,16 +192,52 @@ def test_highlight_regex():
189192
Span(19, 25, "red"), # Turing
190193
]
191194

195+
# As a regular expression object
196+
text = Text("peek-a-boo")
197+
198+
count = text.highlight_regex(re.compile(r"NEVER_MATCH"), "red")
199+
assert count == 0
200+
assert len(text._spans) == 0
201+
202+
# text: peek-a-boo
203+
# indx: 0123456789
204+
count = text.highlight_regex(re.compile(r"[a|e|o]+"), "red")
205+
assert count == 3
206+
assert sorted(text._spans) == [
207+
Span(1, 3, "red"),
208+
Span(5, 6, "red"),
209+
Span(8, 10, "red"),
210+
]
211+
212+
text = Text("Ada Lovelace, Alan Turing")
213+
214+
count = text.highlight_regex(
215+
re.compile(
216+
r"(?P<yellow>[A-Za-z]+)[ ]+(?P<red>[A-Za-z]+)(?P<NEVER_MATCH>NEVER_MATCH)*"
217+
)
218+
)
219+
220+
# The number of matched name should be 2
221+
assert count == 2
222+
assert sorted(text._spans) == [
223+
Span(0, 3, "yellow"), # Ada
224+
Span(4, 12, "red"), # Lovelace
225+
Span(14, 18, "yellow"), # Alan
226+
Span(19, 25, "red"), # Turing
227+
]
228+
192229

193230
def test_highlight_regex_callable():
194231
text = Text("Vulnerability CVE-2018-6543 detected")
195232
re_cve = r"CVE-\d{4}-\d+"
233+
compiled_re_cve = re.compile(r"CVE-\d{4}-\d+")
196234

197235
def get_style(text: str) -> Style:
198236
return Style.parse(
199237
f"bold yellow link https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword={text}"
200238
)
201239

240+
# string
202241
count = text.highlight_regex(re_cve, get_style)
203242
assert count == 1
204243
assert len(text._spans) == 1
@@ -209,6 +248,20 @@ def get_style(text: str) -> Style:
209248
== "https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE-2018-6543"
210249
)
211250

251+
# Clear the tracked _spans for the regular expression object's use
252+
text._spans.clear()
253+
254+
# regular expression object
255+
count = text.highlight_regex(compiled_re_cve, get_style)
256+
assert count == 1
257+
assert len(text._spans) == 1
258+
assert text._spans[0].start == 14
259+
assert text._spans[0].end == 27
260+
assert (
261+
text._spans[0].style.link
262+
== "https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE-2018-6543"
263+
)
264+
212265

213266
def test_highlight_words():
214267
text = Text("Do NOT! touch anything!")

0 commit comments

Comments
 (0)