使用Lua将带引号嵌入的原始字符串解析为列表

通过指定分隔符来解析字符串相对容易。有很多例子。但是,我在解析带有嵌入式双引号或单引号的原始字符串时遇到了麻烦:

item1;item2 "x;y;z";item3 args='arg1;arg2;arg3';item4

当使用 ; 作为分隔符进行拆分时,我希望得到以下结果:

item1
item2 "x;y;z"
item3 args='arg1;arg2;arg3'
item4
点赞
用户1847592
用户1847592
local str = [[item1;item2 "x;y;z";item3 args='arg1;arg2;arg3';;item5]]

for part in ('""'..str..';')
   :gsub(
      "((['\"]).-%2)([^'\"]*)",
      function(q, _, u) return q..u:gsub(";", "\0") end)
   :sub(3)
   :gmatch"(%Z*)%z"
do
   print(part)
end

本地变量 str 存储了一个字符串,其中包含了多个子项,每个子项之间用分号隔开。其中第二个子项包含了一个有多个分号的字符串,其中分号被双引号包围。第三个子项包含了一个有多个分号的字符串,其中分号被单引号和空格包围。

本段代码将字符串 str 按照子项进行分割输出。在分割时,使用 gsub 方法将每个子项中的分号替换成空字符,并将每个子项用 \0 进行分割。然后使用 sub 方法将分割后的字符串前两个字符(即双引号)删除,使用 gmatch 方法进行输出。其中 %Z 匹配除空字符以外的任意字符。

2017-05-01 22:04:51
用户3735873
用户3735873

你也可以采用“老式”的方式来做,即没有内置的模式匹配:

function parse(s,target)
  local line = ''
  local quote
  for c = 1,#s do
    c = s:sub(c,c)
    if c == quote then
      quote = nil
    elseif quote == nil and (c == '"' or c == "'") then
      quote = c
    end
    if quote or c ~= target then
      line = line .. c
    else
      print(line)
      line = ''
    end
  end
  print(line)
end

local s = [[item1;item2 "x;y;z";item3 args='arg1;arg2;arg3';item4]]
parse(s,';')
2017-05-01 23:25:33