Use stdlib re for dialogue matching
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user