Lua:The Frontier pattern: %f

项目中要使用到正则表达式, 但是一般的开源库的正则实现都很庞大, 一个boost的regex的debug版大到了32.9 MB(1.51), 感觉有点不爽。 而lua中的正则实现仅仅只有500行, 也基本满足了大部分需求, 所以就花了点时间看了下lua的实现。 至于lua的正则是和string库一起的, 可以看这里。 

         在了解了lua的正则所能支持的功能后, 看起源码了就水到渠成了(lstrlib.c)。 但还是有两个pattern在网上找不到好的资料。 一个是%b, 一个是%f 。这里就只介绍下这两个pattern. 

%b, %f 两个pattern的关键代码如下:

case L_ESC: {
378       switch (*(p+1)) {
379         case 'b': {  /** balanced string? */
380           s = matchbalance(ms, s, p+2);
381           if (s == NULL) return NULL;
382           p+=4; goto init;  /** else return match(ms, s, p+4); */
383         }
384         case 'f': {  /** frontier? */
385           const char *ep; char previous;
386           p += 2;
387           if (*p != '[')
388             luaL_error(ms->L, "missing " LUA_QL("["" after "
389                                LUA_QL("%%f"" in pattern");
390           ep = classend(ms, p);  /** points to what is next */
391           previous = (s == ms->src_init) ? '\0' : *(s-1);
// s的前一个字符不符合, s当前字符必须符合
392           if (matchbracketclass(uchar(previous), p, ep-1) ||
393              !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
  // p的位置增加了, 但s的位置没有增加
394           p=ep; goto init;  /** else return match(ms, s, ep); */
395         }
396         default: {
397           if (isdigit(uchar(*(p+1)))) {  /** capture results (%0-%9)? */
398             s = match_capture(ms, s, uchar(*(p+1)));
399             if (s == NULL) return NULL;
400             p+=2; goto init;  /** else return match(ms, s, p+2) */
401           }
402           goto dflt;  /** case default */
403         }
404       }
405     }

(1)'%b' 用来匹配对称的字符。常写为 '%bxy' ,x和y是任意两个不同的字符;x作为匹配的开始,y作为匹配的结束。比如,'%b()' 匹配以 '(' 开始,以 ')' 结束的字符串:

print(string.gsub("123abcdefg456", "%bag", ""))
--> 123456


static const char *matchbalance (MatchState *ms, const char *s,
282                                    const char *p) {
283   if (*p == 0 || *(p+1) == 0)
284     luaL_error(ms->L, "unbalanced pattern");
285   if (*s != *p) return NULL;
286   else {
287     int b = *p; // 开始字符 即%bxy中的x
288     int e = *(p+1); // 开始字符 即%bxy中的y
289     int cont = 1;
290     while (++s < ms->src_end) {
291       if (*s == e) {
292         if (--cont == 0) return s+1; //发现一个y
293       }
294       else if (*s == b) cont++; // 发现一个x
295     }
296   }
297   return NULL;  /** string ends out of balance */
298 }

最主要的还是这个 matchbalance , 就是用来找到%bxy中的x和y框起来的部分


(2) %f是一个未被列如lua手册的pattern, 但是作用确实不容小觑。 %f 被叫做frontier pattern 详细见这里

它只有在当前字符要符合要求, 而上个字符不符合要求的情形下才能通过探测, %f只是一个探测功能, 并不影响原字符串的位置

如: 打印出一行中所有全大写的单词

string.gsub ("THE (QUICK) brOWN FOx JUMPS", "%f[%a]%u+%f[%A]", print)

THE
QUICK
JUMPS
%f[%a]表示探测当前位置是“字符”, 上个位置是“非字符”。 后面的%f[%A]表探测当前位置是“非字符”, 上个位置是“字符”
 
一开始探测位置为0即字符T, 上个字符不存在就为'\0'(非字符),%f[%a]通过探测, 因为%f不影响原字符串的位置所以%u+还是从0开始检查。 %u+即以贪婪的方式匹配大写字母, 所以会匹配到索引为3的位置,此时匹配%f[%A], 他要求当前位置为“非字符”, 由于当前位置是空格, 符合; 上个位置为“字符”, 而上个位置为E,也是字符,所以%f[%A]的探测也是成功的, THE就被匹配出来了 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值