繁体   English   中英

寻找基于Lua的解决方案,将字符串拆分为两个或多个组件

[英]looking for a Lua-based solution for splitting a string into two or more components

这是我第一次发布到这个网站,所以请耐心等待。

考虑以下,有点代表性的字符串:

fld u.a. ldfjal \verb*u.a.* dlf \lstinline$u.a.$ u.a. dfla \url{u.a.}rrr

对于某些背景: \\verb*....*\\lstline$...$是LaTeX宏,其参数不是通过匹配大括号分隔的,而是通过公共字符分隔: *\\verb的情况下,和$在的情况下\\lstinline 重要的一点是,分隔符可以是 {} 之外的任何可打印的ASCII字符; 我们不应该假设*$将在所有(甚至任何)情况下用作分隔符。 另外, \\url{...}是一个LaTeX宏,其参数由花括号分隔。 应该假定完整的字符串包含utf8编码的字符; 为简单起见,我们假设它们是纯ASCII字符。

我希望创建一个(希望合理有效的......)基于Lua的方法将完整的字符串分成两组子串:(a)由LaTeX宏及其相关参数组成的部分和(b)另一组部分。 最终的目标是将“其他部分”提供给string.gsub函数调用。

转到前面的示例,如何将字符串分开

fld u.a. ldfjal \verb*u.a.* dlf \lstinline$u.a.$ u.a. dfla \url{u.a.}rrr

进入“Y”(在类似逐字宏的内部)和“N”(不在类似逐字宏的内部)组件,即

NNNNNNNNNNNNNNNNYYYYYYYYYYYNNNNNYYYYYYYYYYYYYYYYNNNNNNNNNNNYYYYYYYYYYNNN

哦,每个完整的字符串都保证有“N”个组件,但可能没有“Y”组件。 原则上,字符串可以以“N”或“Y”分量开始和结束。

我一直试图想出一个使用Lua的字符串库函数的解决方案,但还没有达到目的。 :-(

我们假设:

  • 宏名称只包含字母和@
  • 分隔符可能只是一个数字或标点字符,除了@\\

编码:

-- specify number of parameters for every macro,
-- use negative numbers for macros supporting matching pair of curly braces {} 
local all_macros = {
   verb = 1,
   url = -1,
   lstinline = -1,
   ["@Some@Macros"] = -2,
   makeatletter = 0
}

-- list all the delimiters (only punctuation and digits)
local all_delimiters = [[!"#$%&'*+,-./:;<=>?^_`|~()[]{}0123456789]]

-- specify a function for processing N-part of the string
local function convert(N_substring)
   return N_substring:upper()
end


-- Now do the processing
local s = [[
fld u.a. ldfjal \verb{u.a.{ dlf \lstinline{u.a.} u.a. dfla
\url{u.a.}rrr \@Some@Macros~u.a.~{u.a.}{u.a.}qq\verb|\lstinline+nested use+qqq|q
]]
s = s:gsub("\\([%a@]+)",
   function(macro_name)
      if all_macros[macro_name] then
         return
            "\1\\"..macro_name
            ..(all_macros[macro_name] < 0 and "\2" or "\3")
            :rep(math.abs(all_macros[macro_name]) + 1)
      end
   end
)
repeat
   local old_length = #s
   repeat
      local old_length = #s
      s = s:gsub("\2(\2+)(%b{})", "%2%1")
   until old_length == #s
   s = s:gsub("[\2\3]([\2\3]+)((["..all_delimiters:gsub("%p", "%%%0").."])(.-)%3)", "%2%1")
until old_length == #s
s = ("\2"..s.."\1"):gsub("[\2\3]+([^\2\3]-)\1", convert):gsub("[\1\2\3]", "")

-- Print the result
print(s)

输出:

FLD U.A. LDFJAL \verb{u.a.{ DLF \lstinline{u.a.} U.A. DFLA
\url{u.a.}RRR \@Some@Macros~u.a.~{u.a.}{U.A.}QQ\verb|\lstinline+nested use+qqq|Q

尝试这个:

s=[[
fld u.a. ldfjal \verb*u.a.* dlf \lstinline$u.a.$ u.a. dfla \url{u.a.}rrr
]]

for a,b,c in s:gmatch("(\\verb(.)(.-)%2)") do
    print(a,b,c)
end

你必须为你感兴趣的每个原语做一个循环,但至少分隔符部分会自行处理。

让自己熟悉Lua的字符串模式。

"[^}{]"将匹配任何字符,但例如"}""{"

捕获:

"{([^{}]*)}"这将捕获任意数量的字符,但"{""}"由大括号括起来......

你所要做的就是把所有东西拼凑起来。

https://www.lua.org/pil/20.2.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM