Lua正则相关小记
2016年05月15日 Lua

Lua正则表达式

Lua的正则表达式不是标准的Posix的标准实现,有自己的一些标准,由于长时间不使用,最近用到一个相关的业务逻辑,在一个标签中提取价格,但是这个标签是不规则的,可能前后有很多其他字符(¥XXX priceNum XXX),用固定长度截取显然不成,想到了用正则,最后google了一下,才搞定,但是发现很多都忘记了,这里记录一下。

相关库函数

  • string.find 字符串查找,匹配第一个符合条件的位置与最终位置

    string.gfind是5.0中的函数,在5.1是被标记为deprecated的,在5.2被移除,替换为string.gmatch

  • string.match 匹配第一个符合的字符串

  • string.sub 截取字符串的一部分

  • string.gsub 全局字符串替换,替换目标字符串多次,返回替换后的字符串,同时返回的匹配替换的次数

  • string.gmatch 全局字符串查找,匹配多次符合条件的,并返回一个迭代器,可以在一个for循环里得到所有的匹配

Lua正则元字符

  • 字符类

    % 转义符,转义其他的有特殊意义的元字符串,转义双引号(“)使用反斜杠(\)

    . 匹配任意字符

    %a 所有字母

    %b 边界匹配 如%bse,匹配以s开头e结尾中间的所有

    %c 控制字符,类似响铃,退格,具体参照Wiki

    %d 所有数字

    %l 所有小写

    %u 所有大写

    %p 标点符号

    %s 空白字符,包括空格,四格制表,换行(\r,\n)

    %w 字母和数字

    %x 十六进制数字

    %z 表示0的字符

    大写表示其补集,如%P,表示所有不是标点的。

  • 字符集表示

    使用一对中括号[],中括号内是对应的集合,可以使用-(中划线)表示一个范围

    [0-9A-Za-Z]表示所有字母与数字

  • 匹配次数指示

    指示对应的模式匹配几次

    + 匹配其前面的pattern一次或者多次,按最多长匹配

    * 匹配其前面的pattern0次或者多次,按最长匹配

    - 匹配其前面的pattern0次或者多次,按最短匹配

    ? 匹配其前面的pattern0次或者一次

  • 匹配开头和结尾

    1. 开头,使用^,如^x,匹配以x开头的模式
    2. 结尾,使用$,如x$,匹配以x结尾的模式
  • 捕获指定内容

    使用一对小括号(),捕获指定的内容并返回,用小括号括起对应的模式串

Example

  • 获取标签内价格

    开头说的获取标签内的价格信息,就可以使用string.match匹配对应的字符串,使用小括号捕获想要的内容,使用转义符%转义价格中可能出现的小数点,小数点后可能有数字也可能是一个整数价格,使用*来匹配0个或者多个小数点后的数字,小数前是一定有价格的,不然就不是价格标签了,使用+来匹配至少一个数字,最终得到如下正则表达式:

    pattern = “(%d+%.%d*)”

    1
    2
    3
    4
    local moneyLabel = "¥ 666.02 - 元"
    -- 获取666.02这个价格
    local price = string.match(moneyLabel, "(%d+%.?%d*)")
    print(price) -- 输出666.02
  • string.gsub,模式串替换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    local str = "worse is better"

    local dest, count = string.gsub(str, "%a+", "lua")
    -- 三个单词都被替换成lua,替换次数是3
    print(dest .. " replace count = " .. tostring(count))

    local gsubStr = " something with space "
    -- 第三个参数,捕获对应的前面第几个分组内的匹配串
    local trimStr = string.gsub(gsubStr, "^%s*(.-)%s*$", "%1")
    print(trimStr)

    local matchString = "1 2 3 4"
    -- 第三个参数是把对应前的面捕获的1个替换为4个重复的
    local repeatString = string.gsub(matchString, "(%d+)%s*", "%1 %1 %1 %1 ")
    -- 第个参数表示执行几次替换
    local repeatStringCount = string.gsub(matchString, "(%d+)%s*", "%1+", 2)
    print(repeatString)
    print(repeatStringCount)
  • string.match,匹配串,首次匹配的结果,不是位置

    1
    2
    3
    4
    5
    local tmp = "first1 second2 thrid3"
    local resFromBehind = string.match(tmp, "%d", -2)
    local res = string.match(tmp, "%D+")
    print(resFromBehind) -- 输出3,最后参数指定由右侧第二字符开始匹配
    print(res) -- 输出first,即非数字的其他字符一个或者多个,+是贪婪模式
  • string.find,串查找,首次查找的位置,返回起始结束位置

    1
    2
    3
    4
    5
    6
    local findStr = "phone number: 19922337755"
    -- 第三个参数是查找的起始位置,默认由1开始
    local startIndex, endIndex = string.find(findStr, "%d+", 1)
    print(startIndex, endIndex) -- 输出 15, 25
    local result = string.sub(findStr, startIndex, endIndex)
    print(result) -- 输出 19922337755
  • string.gmatch,串匹配,返回一个迭代器,多次匹配

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    local gmatchStr = "one1, two2, three3, four4, five5"
    -- 包含字母和数字的单词
    for word in string.gmatch(gmatchStr, "%w+") do
    print(word)
    end
    -- 只包含字母的单词
    for onlyLetters in string.gmatch(gmatchStr, "%a+") do
    print(onlyLetters)
    end
    -- 只要数字
    for onlyNums in string.gmatch(gmatchStr, "%d+") do
    print(onlyNums)
    end

记录完毕