Skip to content

Commit 43bf948

Browse files
github-actions[bot]Copilotdbrattliclaude
authored
[Repo Assist] fix(python): fix regex lookbehind patterns being incorrectly converted (#4560)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Dag Brattli <dag@brattli.net> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1d94e4f commit 43bf948

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

src/fable-library-py/fable_library/reg_exp.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ def _options_to_flags(options: int) -> int:
7171
def create(pattern: str, options: int = 0) -> Pattern[str]:
7272
# raw_pattern = pattern.encode("unicode_escape").decode("utf-8")
7373
flags = _options_to_flags(options)
74-
pattern = pattern.replace("?<", "?P<")
74+
# Convert .NET named group syntax (?<name>...) to Python (?P<name>...).
75+
# Only replace ?< when followed by a word character (name start), not by
76+
# = or ! which are part of lookbehind assertions (?<=...) and (?<!...).
77+
pattern = re.sub(r"\?<(?=[A-Za-z_])", "?P<", pattern)
7578
return re.compile(pattern, flags=flags)
7679

7780

tests/Python/TestRegex.fs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,3 +636,17 @@ let ``test doesn't succeed when not existing group without any named groups`` ()
636636
let actual = r.Replace(text, replace)
637637

638638
actual |> equal expected
639+
640+
[<Fact>]
641+
let ``test positive lookbehind works`` () =
642+
let r = Regex @"(?<=A)\w+"
643+
let text = "AB AC AD BD"
644+
let ms = r.Matches(text) |> Seq.map (fun m -> m.Value) |> Seq.toList
645+
ms |> equal [ "B"; "C"; "D" ]
646+
647+
[<Fact>]
648+
let ``test negative lookbehind works`` () =
649+
let r = Regex @"(?<!A)\d"
650+
let text = "A1 B2 A3 C4"
651+
let ms = r.Matches(text) |> Seq.map (fun m -> m.Value) |> Seq.toList
652+
ms |> equal [ "2"; "4" ]

0 commit comments

Comments
 (0)