Skip to content

Commit e218943

Browse files
authored
Improve single quote dialogue regex (#2956)
2 parents 9a9a05c + 9d97c93 commit e218943

2 files changed

Lines changed: 69 additions & 2 deletions

File tree

novelwriter/text/patterns.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,21 @@ def dialogStyle(self) -> re.Pattern | None:
9898
if CONFIG.dialogStyle in (1, 3):
9999
qO = CONFIG.fmtSQuoteOpen.strip()[:1]
100100
qC = CONFIG.fmtSQuoteClose.strip()[:1]
101-
if qO == qC or qC in self.AMBIGUOUS:
101+
if qO == qC:
102102
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
103+
elif qC in self.AMBIGUOUS:
104+
rx.append(f"(?:\\B{qO}[^{qO}]+{qC}\\B(?={qO}|\\s*))")
103105
else:
104106
rx.append(f"(?:{qO}[^{qO}]+{qC})")
105107
if CONFIG.allowOpenDial:
106108
rx.append(f"(?:{qO}.+?$)")
107109
if CONFIG.dialogStyle in (2, 3):
108110
qO = CONFIG.fmtDQuoteOpen.strip()[:1]
109111
qC = CONFIG.fmtDQuoteClose.strip()[:1]
110-
if qO == qC or qC in self.AMBIGUOUS:
112+
if qO == qC:
111113
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
114+
elif qC in self.AMBIGUOUS:
115+
rx.append(f"(?:\\B{qO}[^{qO}]+{qC}\\B(?={qO}|\\s*))")
112116
else:
113117
rx.append(f"(?:{qO}[^{qO}]+{qC})")
114118
if CONFIG.allowOpenDial:

tests/text/test_patterns.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,69 @@ def testTextPatterns_DialogueStyle():
402402
# Single quotes are recognised, double quotes are not
403403
assert allMatches(regEx, "one \u2018two\u2019 three \u201cfour\u201d five") == [[("\u2018two\u2019", 4, 9)]]
404404

405+
# Check detecting closing single quote, see #2633
406+
assert allMatches(
407+
regEx,
408+
"\u2018There\u2019s an author\u2019s evening at the book club,\u2019 "
409+
"she said, \u2018I\u2019m going there tomorrow.\u2019",
410+
) == [
411+
[("\u2018There\u2019s an author\u2019s evening at the book club,\u2019", 0, 47)],
412+
[("\u2018I\u2019m going there tomorrow.\u2019", 58, 85)],
413+
]
414+
415+
assert allMatches(
416+
regEx,
417+
"\u2018There\u2019s an authors\u2019 evening at the book club,\u2019 "
418+
"she said, \u2018I\u2019m going there tomorrow.\u2019",
419+
) == [
420+
[("\u2018There\u2019s an authors\u2019 evening at the book club,\u2019", 0, 47)],
421+
[("\u2018I\u2019m going there tomorrow.\u2019", 58, 85)],
422+
]
423+
424+
assert allMatches(
425+
regEx,
426+
"\u2018There\u2019s an \u201980s authors\u2019 evening at the book club,\u2019 "
427+
"she said, \u2018I\u2019m going there tomorrow.\u2019",
428+
) == [
429+
[("\u2018There\u2019s an \u201980s authors\u2019 evening at the book club,\u2019", 0, 52)],
430+
[("\u2018I\u2019m going there tomorrow.\u2019", 63, 90)],
431+
]
432+
433+
# Using single quotes for double should yield the same result
434+
CONFIG.fmtDQuoteOpen = nwUnicode.U_LSQUO
435+
CONFIG.fmtDQuoteClose = nwUnicode.U_RSQUO
436+
437+
CONFIG.dialogStyle = 2
438+
regEx = REGEX_PATTERNS.dialogStyle
439+
assert regEx is not None
440+
441+
assert allMatches(
442+
regEx,
443+
"\u2018There\u2019s an author\u2019s evening at the book club,\u2019 "
444+
"she said, \u2018I\u2019m going there tomorrow.\u2019",
445+
) == [
446+
[("\u2018There\u2019s an author\u2019s evening at the book club,\u2019", 0, 47)],
447+
[("\u2018I\u2019m going there tomorrow.\u2019", 58, 85)],
448+
]
449+
450+
assert allMatches(
451+
regEx,
452+
"\u2018There\u2019s an authors\u2019 evening at the book club,\u2019 "
453+
"she said, \u2018I\u2019m going there tomorrow.\u2019",
454+
) == [
455+
[("\u2018There\u2019s an authors\u2019 evening at the book club,\u2019", 0, 47)],
456+
[("\u2018I\u2019m going there tomorrow.\u2019", 58, 85)],
457+
]
458+
459+
assert allMatches(
460+
regEx,
461+
"\u2018There\u2019s an \u201980s authors\u2019 evening at the book club,\u2019 "
462+
"she said, \u2018I\u2019m going there tomorrow.\u2019",
463+
) == [
464+
[("\u2018There\u2019s an \u201980s authors\u2019 evening at the book club,\u2019", 0, 52)],
465+
[("\u2018I\u2019m going there tomorrow.\u2019", 63, 90)],
466+
]
467+
405468

406469
@pytest.mark.core
407470
def testTextPatterns_DialoguePlain():

0 commit comments

Comments
 (0)