string.gmatch()不支持匹配首字符
string.gmatch(s, pattern)中,如果s的开头是'^'字符,不会被当成首字符标志,而是被当成一个普通字符。
比如
lua
s="hello world from lua"
for w in string.gmatch(s, "^%a+") do
print(w)
end
不会输出任何内容,而
lua
s="hello world from lua"
for w in string.gmatch(s, "^%a+") do
print(w)
end
会输出^hello。
仿照str_find_aux()的实现修复一下这个问题:
static int gmatch_aux (lua_State *L) {
MatchState ms;
size_t ls;
const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
const char *p = lua_tostring(L, lua_upvalueindex(2));
+ lua_Integer init = lua_tointeger(L, lua_upvalueindex(3));
+ int anchor = 0;
const char *src;
+ if(*p == '^') {
+ if(init != 0) return 0;
+ p++;
+ anchor = 1;
+ }
ms.L = L;
ms.src_init = s;
ms.src_end = s+ls;
- for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
- src <= ms.src_end;
- src++) {
+ for (src = s + init; src < ms.src_end; src++) {
const char *e;
ms.level = 0;
if ((e = match(&ms, src, p)) != NULL) {
lua_Integer newstart = e-s;
if (e == src) newstart++; /* empty match? go at least one position */
lua_pushinteger(L, newstart);
lua_replace(L, lua_upvalueindex(3));
return push_captures(&ms, src, e);
}
+ if (anchor) return 0;
}
return 0; /* not found */
}
手册没说明的前端匹配
前端匹配(frontier matching)的格式:%f[x](其中x是字符集)。这里,方括号内的内容定义了一组字符集,用来描述匹配的前后边界条件。
工作原理:%f[x]会尝试匹配一个位置,假设该位置之前的字符是a,该位置之后的字符是b,则a不属于字符集x,b属于字符集x。
和'^'',$'类似,%f[x]只是去寻找一个位置,而不是特定的字符。
lua
-- 只会匹配第二个123
for w in string.gmatch("0123abc123","%f[%d]123") do
print(w)
end
-- 会匹配两个123
for w in string.gmatch("0123abc123","123") do
print(w)
end