Use stdlib re for dialogue matching

This commit is contained in:
Veronica Berglyd Olsen
2024-09-22 17:34:04 +02:00
parent 9c63f621a8
commit c08033d153
4 changed files with 33 additions and 71 deletions
+5 -7
View File
@@ -33,7 +33,7 @@ from functools import partial
from pathlib import Path
from time import time
from PyQt5.QtCore import QCoreApplication, QRegularExpression
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QFont
from novelwriter import CONFIG
@@ -234,7 +234,7 @@ class Tokenizer(ABC):
nwShortcode.FOOTNOTE_B: self.FMT_FNOTE,
}
self._rxDialogue: list[tuple[QRegularExpression, int, int]] = []
self._rxDialogue: list[tuple[re.Pattern, int, int]] = []
return
@@ -1136,11 +1136,9 @@ class Tokenizer(ABC):
# Match Dialogue
if self._rxDialogue and hDialog:
for regEx, fmtB, fmtE in self._rxDialogue:
rxItt = regEx.globalMatch(text, 0)
while rxItt.hasNext():
rxMatch = rxItt.next()
temp.append((rxMatch.capturedStart(0), 0, fmtB, ""))
temp.append((rxMatch.capturedEnd(0), 0, fmtE, ""))
for match in re.finditer(regEx, text):
temp.append((match.start(0), 0, fmtB, ""))
temp.append((match.end(0), 0, fmtE, ""))
# Post-process text and format
result = text
+10 -24
View File
@@ -29,7 +29,7 @@ import re
from time import time
from PyQt5.QtCore import QRegularExpression, Qt
from PyQt5.QtCore import Qt
from PyQt5.QtGui import (
QBrush, QColor, QFont, QSyntaxHighlighter, QTextBlockUserData,
QTextCharFormat, QTextDocument
@@ -398,29 +398,15 @@ class GuiDocHighlighter(QSyntaxHighlighter):
if hRules:
for rX, hRule in hRules:
if isinstance(rX, QRegularExpression):
rxItt = rX.globalMatch(text, xOff)
while rxItt.hasNext():
rxMatch = rxItt.next()
for xM, hFmt in hRule.items():
xPos = rxMatch.capturedStart(xM)
xEnd = rxMatch.capturedEnd(xM)
for x in range(xPos, xEnd):
cFmt = self.format(x)
if cFmt.fontStyleName() != "markup":
cFmt.merge(hFmt)
self.setFormat(x, 1, cFmt)
else:
for match in re.finditer(rX, text[xOff:]):
for xM, hFmt in hRule.items():
# print(f"'{match.group(xM)}'", match.start(xM), match.end(xM))
xPos = match.start(xM) + xOff
xEnd = match.end(xM) + xOff
for x in range(xPos, xEnd):
cFmt = self.format(x)
if cFmt.fontStyleName() != "markup":
cFmt.merge(hFmt)
self.setFormat(x, 1, cFmt)
for match in re.finditer(rX, text[xOff:]):
for xM, hFmt in hRule.items():
xPos = match.start(xM) + xOff
xEnd = match.end(xM) + xOff
for x in range(xPos, xEnd):
cFmt = self.format(x)
if cFmt.fontStyleName() != "markup":
cFmt.merge(hFmt)
self.setFormat(x, 1, cFmt)
data = self.currentBlockUserData()
if not isinstance(data, TextBlockData):
+12 -23
View File
@@ -25,11 +25,8 @@ from __future__ import annotations
import re
from PyQt5.QtCore import QRegularExpression
from novelwriter import CONFIG
from novelwriter.constants import nwRegEx
from novelwriter.types import QRegExUnicode
class RegExPatterns:
@@ -67,7 +64,7 @@ class RegExPatterns:
return self._rxSCValue
@property
def dialogStyle(self) -> QRegularExpression:
def dialogStyle(self) -> re.Pattern:
"""Dialogue detection rule based on user settings."""
symO = ""
symC = ""
@@ -79,34 +76,26 @@ class RegExPatterns:
symC += CONFIG.fmtDQuoteClose
rxEnd = "|$" if CONFIG.allowOpenDial else ""
rxRule = QRegularExpression(f"\\B[{symO}].*?(?:[{symC}]\\B{rxEnd})")
rxRule.setPatternOptions(QRegExUnicode)
return rxRule
return re.compile(f"\\B[{symO}].*?(?:[{symC}]\\B{rxEnd})", re.UNICODE)
@property
def dialogLine(self) -> QRegularExpression:
def dialogLine(self) -> re.Pattern:
"""Dialogue line rule based on user settings."""
sym = QRegularExpression.escape(CONFIG.dialogLine)
rxRule = QRegularExpression(f"^{sym}.*?$")
rxRule.setPatternOptions(QRegExUnicode)
return rxRule
sym = re.escape(CONFIG.dialogLine)
return re.compile(f"^{sym}.*?$", re.UNICODE)
@property
def narratorBreak(self) -> QRegularExpression:
def narratorBreak(self) -> re.Pattern:
"""Dialogue narrator break rule based on user settings."""
sym = QRegularExpression.escape(CONFIG.narratorBreak)
rxRule = QRegularExpression(f"\\B{sym}\\S.*?\\S{sym}\\B")
rxRule.setPatternOptions(QRegExUnicode)
return rxRule
sym = re.escape(CONFIG.narratorBreak)
return re.compile(f"\\B{sym}\\S.*?\\S{sym}\\B", re.UNICODE)
@property
def altDialogStyle(self) -> QRegularExpression:
def altDialogStyle(self) -> re.Pattern:
"""Dialogue alternative rule based on user settings."""
symO = QRegularExpression.escape(CONFIG.altDialogOpen)
symC = QRegularExpression.escape(CONFIG.altDialogClose)
rxRule = QRegularExpression(f"\\B{symO}.*?{symC}\\B")
rxRule.setPatternOptions(QRegExUnicode)
return rxRule
symO = re.escape(CONFIG.altDialogOpen)
symC = re.escape(CONFIG.altDialogClose)
return re.compile(f"\\B{symO}.*?{symC}\\B", re.UNICODE)
REGEX_PATTERNS = RegExPatterns()
+6 -17
View File
@@ -24,30 +24,19 @@ import re
import pytest
from PyQt5.QtCore import QRegularExpression
from novelwriter import CONFIG
from novelwriter.constants import nwUnicode
from novelwriter.text.patterns import REGEX_PATTERNS
def allMatches(regEx: QRegularExpression, text: str) -> list[list[str]]:
def allMatches(regEx: re.Pattern, text: str) -> list[list[str]]:
"""Get all matches for a regex."""
result = []
if isinstance(regEx, QRegularExpression):
itt = regEx.globalMatch(text, 0)
while itt.hasNext():
match = itt.next()
result.append([
(match.captured(n), match.capturedStart(n), match.capturedEnd(n))
for n in range(match.lastCapturedIndex() + 1)
])
else:
for match in re.finditer(regEx, text):
result.append([
(match.group(n), match.start(n), match.end(n))
for n in range((match.lastindex or -1) + 1)
])
for match in re.finditer(regEx, text):
result.append([
(match.group(n), match.start(n), match.end(n))
for n in range((match.lastindex or 0) + 1)
])
return result