鍍金池/ 教程/ Java/ 正則表達(dá)式
定時(shí)任務(wù)
函數(shù)的參數(shù)
超時(shí)
一個(gè) openresty 內(nèi)存“泄漏”問題
獲取 uri 參數(shù)
局部變量
sleep
灰度發(fā)布
TIME_WAIT
代碼覆蓋率
連接池
CentOS 平臺(tái)安裝
稀疏數(shù)組
如何只啟動(dòng)一個(gè) timer 工作?
變量的共享范圍
break,return 關(guān)鍵字
Nginx
SQL 注入
如何引用第三方 resty 庫(kù)
不同階段共享變量
獲取請(qǐng)求 body
動(dòng)態(tài)生成的 lua-resty-redis 模塊方法
動(dòng)態(tài)加載證書和 OCSP stapling
repeat 控制結(jié)構(gòu)
編碼為 array 還是 object
Nginx 靜態(tài)文件服務(wù)
執(zhí)行階段概念
Lua 函數(shù)
日期時(shí)間函數(shù)
健康監(jiān)測(cè)
與其他 location 配合
for 控制結(jié)構(gòu)
函數(shù)定義
HTTPS 時(shí)代
點(diǎn)號(hào)與冒號(hào)操作符的區(qū)別
String 庫(kù)
文件操作
OpenResty 最佳實(shí)踐
<code>ngx.shared.DICT</code> 非隊(duì)列性質(zhì)
使用動(dòng)態(tài) DNS 來完成 HTTP 請(qǐng)求
代碼規(guī)范
什么是 JIT?
Windows 平臺(tái)安裝
正確的記錄日志
LuaNginxModule
不用標(biāo)準(zhǔn)庫(kù)
C10K 編程
控制結(jié)構(gòu)
請(qǐng)求中斷后的處理
Lua 環(huán)境搭建
Test::Nginx 能指定現(xiàn)成的 nginx.conf,而不是自動(dòng)生成一個(gè)嗎
Lua 基礎(chǔ)數(shù)據(jù)類型
動(dòng)態(tài)限速
PostgresNginxModule
簡(jiǎn)單API Server框架
API 測(cè)試
location 匹配規(guī)則
虛變量
單元測(cè)試
防止 SQL 注入
select + set_keepalive 組合操作引起的數(shù)據(jù)讀寫錯(cuò)誤
阻塞操作
全動(dòng)態(tài)函數(shù)調(diào)用
Web 服務(wù)
典型應(yīng)用場(chǎng)景
Nginx 新手起步
TLS session resumption
輸出響應(yīng)體
調(diào)用代碼前先定義函數(shù)
module 是邪惡的
怎樣理解 cosocket
模塊
Socket 編程發(fā)展
如何對(duì) Nginx Lua module 添加新 api
如何在后臺(tái)開啟輕量級(jí)線程完成定時(shí)任務(wù)?
如何定位問題
table 庫(kù)
json 解析的異常捕獲
如何安裝火焰圖生成工具
lua 中如何 continue
if 是邪惡的
為什么我們的域名不能被解析
抵制使用 module() 定義模塊
測(cè)試
body 在 location 中的傳遞
Lua 入門
子查詢
pipeline 壓縮請(qǐng)求數(shù)量
如何發(fā)起新 HTTP 請(qǐng)求
Lua 簡(jiǎn)介
緩存失效風(fēng)暴
Ubuntu 平臺(tái)安裝
日志輸出
緩存
Lua 面向?qū)ο缶幊?/span>
Nginx 陷阱和常見錯(cuò)誤
Redis 接口的二次封裝(發(fā)布訂閱)
日志
訪問有授權(quán)驗(yàn)證的 Redis
正則表達(dá)式
lock
熱裝載代碼
調(diào)用 FFI 出現(xiàn) &quot;table overflow&quot;
數(shù)據(jù)合法性檢測(cè)
禁止某些終端訪問
控制結(jié)構(gòu) if-else
調(diào)試
與 Docker 使用的網(wǎng)絡(luò)瓶頸
PostgresNginxModule 模塊的調(diào)用方式
用 do-end 整理你的代碼
FFI
什么時(shí)候使用
簡(jiǎn)介
環(huán)境搭建
Mac OS X 平臺(tái)安裝
火焰圖
負(fù)載均衡
while 型控制結(jié)構(gòu)
如何定位 openresty 崩潰 bug
使用 Nginx 內(nèi)置綁定變量
判斷數(shù)組大小
請(qǐng)求返回后繼續(xù)執(zhí)行
Redis 接口的二次封裝
KeepAlive
反向代理
協(xié)議無痛升級(jí)
數(shù)學(xué)庫(kù)
元表
Vanilla 介紹
HelloWorld
LuaCjsonLibrary
持續(xù)集成
代碼靜態(tài)分析
網(wǎng)上有大量對(duì) Lua 調(diào)優(yōu)的推薦,我們應(yīng)該如何看待?
script 壓縮復(fù)雜請(qǐng)求
非空判斷
性能測(cè)試
函數(shù)返回值
API 的設(shè)計(jì)
kong 介紹
表達(dá)式
不支持事務(wù)
LuaRestyDNSLibrary 簡(jiǎn)介

正則表達(dá)式

OpenResty 中,同時(shí)存在兩套正則表達(dá)式規(guī)范:Lua 語(yǔ)言的規(guī)范和 ngx.re.* 的規(guī)范,即使您對(duì) Lua 語(yǔ)言中的規(guī)范非常熟悉,我們?nèi)圆唤ㄗh使用 Lua 中的正則表達(dá)式。一是因?yàn)?Lua 中正則表達(dá)式的性能并不如 ngx.re.* 中的正則表達(dá)式優(yōu)秀;二是 Lua 中的正則表達(dá)式并不符合 POSIX 規(guī)范,而 ngx.re.* 中實(shí)現(xiàn)的是標(biāo)準(zhǔn)的 POSIX 規(guī)范,后者明顯更具備通用性。

Lua 中的正則表達(dá)式與 Nginx 中的正則表達(dá)式相比,有 5% - 15% 的性能損失,而且 Lua 將表達(dá)式編譯成 Pattern 之后,并不會(huì)將 Pattern 緩存,而是每此使用都重新編譯一遍,潛在地降低了性能。ngx.re.* 中的正則表達(dá)式可以通過參數(shù)緩存編譯過后的 Pattern,不會(huì)有類似的性能損失。

ngx.re.* 中的 o 選項(xiàng),指明該參數(shù),被編譯的 Pattern 將會(huì)在工作進(jìn)程中緩存,并且被當(dāng)前工作進(jìn)程的每次請(qǐng)求所共享。Pattern 緩存的上限值通過 lua_regex_cache_max_entries 來修改。

ngx.re.* 中的 j 選項(xiàng),指明該參數(shù),如果使用的 PCRE 庫(kù)支持 JIT,OpenResty 會(huì)在編譯 Pattern 時(shí)啟用 JIT。啟用 JIT 后正則匹配會(huì)有明顯的性能提升。較新的平臺(tái),自帶的 PCRE 庫(kù)均支持 JIT。如果系統(tǒng)自帶的 PCRE 庫(kù)不支持 JIT,出于性能考慮,最好自己編譯一份 libpcre.so,然后在編譯 OpenResty 時(shí)鏈接過去。要想驗(yàn)證當(dāng)前 PCRE 庫(kù)是否支持 JIT,可以這么做

  1. 編譯 OpenResty 時(shí)在 ./configure 中指定 --with-debug 選項(xiàng)
  2. error_log 指令中指定日志級(jí)別為 debug
  3. 運(yùn)行正則匹配代碼,查看日志中是否有 pcre JIT compiling result: 1

即使運(yùn)行在不支持 JIT 的 OpenResty 上,加上 j 選項(xiàng)也不會(huì)帶來壞的影響。在 OpenResty 官方的 Lua 庫(kù)中,正則匹配至少都會(huì)帶上 jo 這兩個(gè)選項(xiàng)。

location /test {
    content_by_lua_block {
        local regex = [[\d+]]

        -- 參數(shù) "j" 啟用 JIT 編譯,參數(shù) "o" 是開啟緩存必須的
        local m = ngx.re.match("hello, 1234", regex, "jo")
        if m then
            ngx.say(m[0])
        else
            ngx.say("not matched!")
        end
    }
}

測(cè)試結(jié)果如下:

?  ~ curl 127.0.0.1/test
1234

另外還可以試試引入 lua-resty-core 中的正則表達(dá)式 API。這么做需要在代碼里加入 require 'resty.core.regex'lua-resty-core 版本的 ngx.re.*,是通過 FFI 而非 Lua/C API 來跟 OpenResty C 代碼交互的。某些情況下,會(huì)帶來明顯的性能提升。

Lua 正則簡(jiǎn)單匯總

Lua 中正則表達(dá)式語(yǔ)法上最大的區(qū)別,Lua 使用 '%' 來進(jìn)行轉(zhuǎn)義,而其他語(yǔ)言的正則表達(dá)式使用 '\' 符號(hào)來進(jìn)行轉(zhuǎn)義。其次,Lua 中并不使用 '?' 來表示非貪婪匹配,而是定義了不同的字符來表示是否是貪婪匹配。定義如下:

符號(hào) 匹配次數(shù) 匹配模式
+ 匹配前一字符 1 次或多次 非貪婪
* 匹配前一字符 0 次或多次 貪婪
- 匹配前一字符 0 次或多次 非貪婪
? 匹配前一字符 0 次或1次 僅用于此,不用于標(biāo)識(shí)是否貪婪
符號(hào) 匹配模式
. 任意字符
%a 字母
%c 控制字符
%d 數(shù)字
%l 小寫字母
%p 標(biāo)點(diǎn)字符
%s 空白符
%u 大寫字母
%w 字母和數(shù)字
%x 十六進(jìn)制數(shù)字
%z 代表 0 的字符
  • string.find 的基本應(yīng)用是在目標(biāo)串內(nèi)搜索匹配指定的模式的串。函數(shù)如果找到匹配的串,就返回它的開始索引和結(jié)束索引,否則返回 nil。find 函數(shù)第三個(gè)參數(shù)是可選的:標(biāo)示目標(biāo)串中搜索的起始位置,例如當(dāng)我們想實(shí)現(xiàn)一個(gè)迭代器時(shí),可以傳進(jìn)上一次調(diào)用時(shí)的結(jié)束索引,如果返回了一個(gè) nil 值的話,說明查找結(jié)束了.
local s = "hello world"
local i, j = string.find(s, "hello")
print(i, j) --> 1 5
  • string.gmatch 我們也可以使用返回迭代器的方式。
local s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
    print(w)
end

-- output :
--    hello
--    world
--    from
--    Lua
  • string.gsub 用來查找匹配模式的串,并將使用替換串其替換掉,但并不修改原字符串,而是返回一個(gè)修改后的字符串的副本,函數(shù)有目標(biāo)串,模式串,替換串三個(gè)參數(shù),使用范例如下:
local a = "Lua is cute"
local b = string.gsub(a, "cute", "great")
print(a) --> Lua is cute
print(b) --> Lua is great
  • 還有一點(diǎn)值得注意的是,'%b' 用來匹配對(duì)稱的字符,而不是一般正則表達(dá)式中的單詞的開始、結(jié)束。 '%b' 用來匹配對(duì)稱的字符,而且采用貪婪匹配。常寫為 '%bxy',x 和 y 是任意兩個(gè)不同的字符;x 作為 匹配的開始,y 作為匹配的結(jié)束。比如,'%b()' 匹配以 '(' 開始,以 ')' 結(jié)束的字符串:
print(string.gsub("a (enclosed (in) parentheses) line", "%b()", ""))

-- output: a  line 1