尝试从Lua中的字符串中获取某种键值数据

huangapple go评论60阅读模式
英文:

Trying to get some kind of key:value data from a string in Lua

问题

我又遇到问题了,因为模式……所以让我们看看是否可以得到一点帮助。问题是,我有一个由函数返回的字符串,其中包含以下内容:

📄 我的脚本
脚本ID:RL_SimpleTest
版本:0.0.1
脚本类型:菜单脚本
另一个键:另一个值
也许还有一些文本...

我想逐行解析它,如果行包含“:”,则将行的左侧内容(k)和右侧内容(v)分别放入两个变量中。例如,对于第二行(第一行应该被忽略),k 包含“脚本ID”,v 包含“RL_SimpleTest”等等。

嗯,我开始尝试了以下代码:

function RL_Test:StringToKeyValue(str, sep1, sep2)
	sep1 = sep1 or "\n"
	sep2 = sep2 or ":"
	local t = {}
	for line in string.gmatch(str, "([^" .. sep1 .. "]+)") do
		print(line)
		for k in string.gmatch(line, "([^" .. sep2 .. "]+)") do --在这里,我迷失在尝试分别获取键/值对并同时处理它们...
			--t[k] = v
			print(k)
		end
	end
	return t
end

希望一旦我孤立出包含我想提取的以键/值形式存在的数据的行,我就能够做一些类似for k, v in string.gmatch(line, "([^" .. sep2 .. "]+)")的操作,这样就能获取到两个数据片段。但是当然这行不通,虽然我有一种感觉这是一个微不足道的问题,但是我甚至不知道从哪里开始,始终缺乏对模式的理解...

希望至少我表达清楚了。提前感谢任何帮助。

英文:

I'm (again) stuck because patterns... so let's see if with a little of help... The case is I have e. g. a string returned by a function that contains the following:

📄 My Script
ScriptID:RL_SimpleTest
Version:0.0.1
ScriptType:MenuScript
AnotherKey:AnotherValue
And, maybe, some more text...

And I'd want to parse it line by line and should the line contains a ":" get the left side content of the line in a variable (k) and the right content in another one (v), so e. g. I'd have k containing "ScriptID" and v containing "RL_SimpleTest" for the second line (the first one should be just ignored) and so on...

Well, I've started with something like this:

function RL_Test:StringToKeyValue(str, sep1, sep2)
	sep1 = sep1 or "\n"
	sep2 = sep2 or ":"
	local t = {}
	for line in string.gmatch(str, "([^" .. sep1 .. "]+)") do
		print(line)
		for k in string.gmatch(line, "([^" .. sep2 .. "]+)") do --Here is where I'm lost trying to get the key/value pair separately and at the same time...
			--t[k] = v
			print(k)
		end
	end
	return t
end

With the hope once I got isolated the line containing the data in the key:value form that I want to extract, I'd be able to do some kind of for k, v in string.gmatch(line, "([^" .. sep2 .. "]+)") or something so and that way get the two pieces of data, but of course it doesn't work and even though I have a feeling it's a triviality I don't know even where to start, always for the lack of patterns understanding...

Well, I hope at least I exposed it right... Thanks in advance for any help.

答案1

得分: 2

    local t = {}
    for line in (s..'\n'):gmatch("(.-)\r?\n") do
      for a, b in line:gmatch("([^:]+):([^:\n\r]+)") do
        t[a] = b
      end
    end
英文:
local t = {}
for line in (s..'\n'):gmatch("(.-)\r?\n") do
  for a, b in line:gmatch("([^:]+):([^:\n\r]+)") do
    t[a] = b
  end
end

The pattern is quite simple. Match anything that is not a colon that is followed by a colon that is followed by anything that is not a colon or a line break. Put what you want in captures and you're done.

答案2

得分: 1

假设每行的格式都是`k:v`,包含一个冒号,或者不包含冒号(没有k/v对)。

然后,你可以首先使用`[^\n]+`(假定使用UNIX LF换行符)匹配非空行,然后使用`^([^:]+):([^:]+)$`匹配每一行。对第二个模式的分解如下:

 * `^`  `$`  *锚点*。它们强制模式匹配整行。
 * `([^:]+)` 匹配并捕获一个或多个非分号字符。

这将使你得到:

```lua
function RL_Test:StringToKeyValue(str)
    local t = {}
    for line in str:gmatch"[^\n]+" do
        local k, v = line:match"^([^:]+):([^:]+)$"
        if k then -- 行是k:v对吗?
           t[k] = v
        end
    end
    return t
end

如果你想支持Windows CRLF换行符,可以使用for line in (s..'\n'):gmatch'(.-)\r?\n' do,就像Piglet的回答中用于匹配行的方式一样。

这个回答与Piglet的回答不同之处在于它使用match而不是gmatch来匹配k/v对,允许每行 恰好 有一个k/v对, 恰好 有一个冒号,而Piglet的代码可能会提取多个k/v对。


<details>
<summary>英文:</summary>

I assume every line is of the format `k:v`, containing exactly one colon, or containing no colon (no k/v pair).

Then you can simply first match nonempty lines using `[^\n]+` (assuming UNIX LF line endings), then match each line using `^([^:]+):([^:]+)$`. Breakdown of the second pattern:

 * `^` and `$` are *anchors*. They force the pattern to match the entire line.
 * `([^:]+)` matches &amp; captures one or more non-semicolon characters.

This leaves you with:

```lua
function RL_Test:StringToKeyValue(str)
    local t = {}
    for line in str:gmatch&quot;[^\n]+&quot; do
        local k, v = line:match&quot;^([^:]+):([^:]+)$&quot;
        if k then -- line is k:v pair?
           t[k] = v
        end
    end
    return t
end

If you want to support Windows CRLF line endings, use for line in (s..&#39;\n&#39;):gmatch&#39;(.-)\r?\n&#39; do as in Piglet's answer for matching the lines instead.

This answer differs from Piglet's answer in that it uses match instead of gmatch for matching the k/v pairs, allowing exactly one k/v pair with exactly one colon per line, whereas Piglet's code may extract multiple k/v pairs per line.

huangapple
  • 本文由 发表于 2023年2月8日 12:25:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75381373.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定