如何从 Lua 中以另一个字符串开头的字符串中删除行?例如,我想从字符串中删除所有result
以单词开头的行<Table
。这是我到目前为止写的代码:
for line in result:gmatch"<Table [^\n]*" do line = "" end
如何从 Lua 中以另一个字符串开头的字符串中删除行?例如,我想从字符串中删除所有result
以单词开头的行<Table
。这是我到目前为止写的代码:
for line in result:gmatch"<Table [^\n]*" do line = "" end
其他答案为实际从字符串中剥离行提供了很好的解决方案,但没有解决您的代码无法做到这一点的原因。
为清楚起见重新格式化,您写道:
for line in result:gmatch"<Table [^\n]*" do
line = ""
end
第一部分是一种合理的方式来迭代result
和提取所有以开头<Table
并继续到但不包括下一个换行符的文本范围。gmatch
由返回的迭代器在每次调用时返回匹配文本的副本line
,并且局部变量保存该副本作为for
循环体。
由于匹配的文本被复制到 中line
,因此对 的更改line
不会也不能修改存储在 中的实际文本result
。
这是由于 Lua 字符串的一个更基本的属性。Lua 中的所有字符串都是不可变的。一旦存储,就无法更改。保存字符串的变量实际上是保存一个指向引用计数的不可变字符串内部表的指针,它只允许两个操作:新字符串的内部化,以及删除没有剩余引用的内部化字符串。
因此,任何编辑存储在其中的字符串内容的方法result
都需要创建一个全新的字符串。Wherestring.gmatch
提供了对内容的迭代但不允许对其进行更改,string.gsub
提供创建一个新字符串,其中与模式匹配的所有文本都已被新内容替换。但甚至string.gsub
没有改变不可变的源文本;它正在创建一个新的不可变字符串,它是旧字符串的副本,并进行了替换。
使用gsub
可以像这样简单:
result = result:gsub("<Table [^\n]*", "")
但这会暴露模式本身的其他缺陷。首先,也是最明显的,没有什么要求模式只在行首匹配。其次,该模式不包含换行符,因此它将保留该行但为空。
所有这些都可以通过仔细和巧妙地使用模式库来改进。但这并没有改变您从 XML 文本开始并且没有使用 XML 感知工具处理它的事实。在这种情况下,任何基于模式匹配甚至正则表达式的方法都可能以失败告终。
string.gmtach
用于获取模式的所有出现。要替换某些模式,您需要使用string.gsub
.
另一个问题是您的模式<Table [^\n]*
将匹配包含单词的所有行<Table
,而不仅仅是以它开头。
Lua 模式不支持行锚的开头,这几乎可以工作:
local str = result:gsub("\n<Table [^\n]*", "")
除了它会错过第一行。我的解决方案是使用第二次运行来测试第一行:
local str1 = result:gsub("\n<Table [^\n]*", "")
local str2 = str1:gsub("^<Table [^\n]*\n", "")
LPEG库非常适合此类任务。只需编写一个函数来创建自定义线剥离器:
local mk_striplines
do
local lpeg = require "lpeg"
local P = lpeg.P
local Cs = lpeg.Cs
local lpegmatch = lpeg.match
local eol = P"\n\r" + P"\r\n" + P"\n" + P"\t"
local eof = P(-1)
local linerest = (1 - eol)^1 * (eol + eof) + eol
mk_striplines = function (pat)
pat = P (pat)
local matchline = pat * linerest
local striplines = Cs (((matchline / "") + linerest)^1)
return function (str)
return lpegmatch (striplines, str)
end
end
end
请注意,参数 tomk_striplines()
可能是字符串或模式。因此,结果非常灵活:
mk_striplines (P"<Table" + P"</Table>")
将创建一个剥离器,该剥离器会丢弃具有两种不同图案的线条。
mk_striplines (P"x" * P"y"^0)
删除以 an 开头的每一行,
x
后跟任意数量的y
' - 你明白了。
使用示例:
local linestripper = mk_striplines "foo"
local test = [[
foo lorem ipsum
bar baz
buzz
foo bar
xyzzy
]]
print (linestripper (test))
result = result:gsub('%f[^\n%z]<Table [^\n]*', '')
此模式的开头'%f[^\n%z]
, 是一个边界模式,它将匹配从换行符或零字符到另一个字符的任何转换,并且对于边界模式,前第一个字符计为零字符。换句话说,使用该前缀允许模式的其余部分在第一行或任何其他行首匹配。