lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It seems there is a bug in string.gfind. It does not handle `^' anchor. Look
at the following code:

s = "abc 123"
t = "123 abc"

print(string.find(s, "(%d+)"))
-- 5       7       123 (ok)
print(string.find(s, "^(%d+)"))
-- nil (ok)
print(string.find(t, "(%d+)"))
-- 1       3       123 (ok)
print(string.find(t, "^(%d+)"))
-- 1       3       123 (ok)

print()
print(string.gsub(s, "(%d+)", 789))
-- abc 789 1 (ok)
print(string.gsub(s, "^(%d+)", 789))
-- abc 123 0 (ok)
print(string.gsub(t, "(%d+)", 789))
-- 789 abc 1 (ok)
print(string.gsub(t, "^(%d+)", 789))
-- 789 abc 1 (ok)

print()
for z in string.gfind(s, "(%d+)") do print(z) end
-- 123 (ok)
for z in string.gfind(s, "^(%d+)") do print(z) end
-- (nothing, ok)
for z in string.gfind(t, "(%d+)") do print(z) end
-- 123 (ok)
for z in string.gfind(t, "^(%d+)") do print(z) end
-- (nothing, wrong !!! should be: `123')


And here is a patch to get gfind work as expected:

/* in lstrlib.c */

static int gfind_aux (lua_State *L) {
  MatchState ms;
  const char *s = lua_tostring(L, lua_upvalueindex(1));
  size_t ls = lua_strlen(L, lua_upvalueindex(1));
  const char *p = lua_tostring(L, lua_upvalueindex(2));
  const char *src;
/* BEGIN PATCH */
  int anchor = (*p == '^') ? (p++, 1) : 0;
/* END PATCH */
  ms.L = L;
  ms.src_init = s;
  ms.src_end = s+ls;
  for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3));
       src <= ms.src_end;
       src++) {
    const char *e;
    ms.level = 0;
    if ((e = match(&ms, src, p)) != NULL) {
      int newstart = e-s;
      if (e == src) newstart++;  /* empty match? go at least one position */
      lua_pushnumber(L, (lua_Number)newstart);
      lua_replace(L, lua_upvalueindex(3));
      return push_captures(&ms, src, e);
    }
/* BEGIN PATCH */
    if (anchor) break;
/* END PATCH */
  }
  return 0;  /* not found */
}

Regards,
Leszek Buczkowski