ReviewOS

zig-utils/zig-regex

Doesn't "?" support non-greedy mode?

#1
Closed babybabycloud opened this 9 days ago ·
9 days ago

Hi,

I have such a code snippet,

const std = ;
const regex = ;

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    var pattern = try regex.Regex.compile(arena.child_allocator, "\\$t\\((.*)\\)");
    const target = "$t(common.hello) abc $t(common.name)";
    try search(arena.child_allocator, target, pattern);
    pattern = try regex.Regex.compile(arena.child_allocator, "\\$t\\((.*?)\\)");
    try search(arena.child_allocator, target, pattern);
}

fn search(allocator: std.mem.Allocator, target: []const u8, re: regex.Regex) !void {
    const matches = try re.findAll(allocator, target);
    for (matches) |m| {
        for (m.captures) |cap| {
            std.debug.print("{s}\n", .{cap});
        }
    }
}

and its output is as below

zig-out/bin/translator
common.hello) abc $t(common.name

It seems that the question mark makes it find nothing.

And what I expect should be "common.hello" and "common.name" (without quote mark).

Is this a issue of zig-regex?

Yes, it does resolve the issue to replace the pattern "\$t\((.)\)" with "\$t\((\S)\)", however it cannot handle "$t(common.hello)$t(common.name)"

9 days ago

Yes, this was a zig-regex issue, my sincere apologies!

First off, thanks for reporting this! The bug was in the backtracking engine - lazy quantifiers (.*?, .+?, etc.) were not properly backtracking when used inside find() / findAll()

As you can see above, the fix has now been merged and both patterns now work correctly:

  • \$t\((.*?)\) - lazy quantifier, finds minimal matches
  • \$t\((\S*)\) - non-whitespace workaround (also now works for adjacent matches like $t(common.hello)$t(common.name))

There was also a secondary bug where capture group positions were incorrect for the 2nd+ match in findAll, which has been fixed as well 😬

Anyways, thanks again!

Sign in to comment on this issue.