我曾经使用简单的方法迭代字符串中的行
for line in s:gmatch("[^\r\n]+") do
效果非常好!然后现实生活发生了......
...现在我的要求发生了变化:我也需要匹配空行。问题是:由于这种形式的迭代在多个位置使用,而这些位置本身就是丛林,所以我想尽可能避免更改周围的代码。到目前为止,我对 gmatch
/find
的尝试还无法为上述模式创建“直接”替换,因为上述函数无法实现的微妙期望来匹配。
我寻求的构造(for line in some_matcher(s) do
)符合以下要求,我相信这些要求涵盖了我担心的所有边缘情况:
INPUT EXPECTATIONS
1. '' -- match once ('')
2. '\r\n' -- match twice ('', '')
3. '\r\n\r\n' -- match thrice ('', '', '')
4. 'aaa' -- match once ('aaa')
5. 'aaa\r\n' -- match twice ('aaa', '')
6. 'aaa\r\nbbb' -- match twice ('aaa', 'bbb')
7. '\r\nbbb' -- match twice ('', 'bbb')
我的旧解决方案假设仅发生 \r\n
行结尾,如果新解决方案仅处理该场景,则完全没问题。
但是,由于我的商店正在谈论 Linux 支持计划,因此非常感谢并保存一个也处理更简单的 \n
行结尾(为了将来的 unix 兼容性)的答案几个月后重新审视这个问题。然而,问题是,在许多情况下,我需要原始字符串输入中的此匹配的起始列。如果上面的构造(for ... do
)可以输出它作为一个额外的好处,那就特别棒了。
最佳答案
如果您需要以跨平台方式准确检测换行符边界而不是跳过/丢弃它们,则不能使用同时包含 \r
和 \n
,因为它将匹配换行符序列 \r\n
两次而不是一次(CRLF 在 DOS/Windows 上是单个换行符)。您可以使用足够强大的正则表达式引擎(例如支持交替)来处理这个问题,但 Lua 的模式匹配库非常少。
最好的选择是在处理文本之前规范换行符,如下所示:
function normalize_eols(s)
return s
:gsub('\r\n','\n')
:gsub('\r', '\n')
end
对于您的输入=>输出网格,如果我们将换行符视为行分隔符,那么我期望[^\n]*
(零或更多非换行符)可以工作,但我们得到以下结果:
'' => ('')
'\n' => ('', '')
'\n\n' => ('', '', '')
'aaa' => ('aaa', '')
'aaa\n' => ('aaa', '', '')
'aaa\nbbb' => ('aaa', '', 'bbb', '')
'\nbbb' => ('', 'bbb', '')
老实说,我不知道为什么。
但是,如果我们将换行符视为行终止符,那么我们可以通过将换行符附加到输入并使用模式 [^\n] 来获得您想要的结果*\n
(零个或多个非换行符,后跟换行符):
'\n' => ('')
'\n\n' => ('', '')
'\n\n\n' => ('', '', '')
'aaa\n' => ('aaa')
'aaa\n\n' => ('aaa', '')
'aaa\nbbb\n' => ('aaa', 'bbb')
'\nbbb\n' => ('', 'bbb')
所以你的代码将更改为:
s = normalize_eols(s) .. '\n'
for line in s:gmatch('([^\n]*)\n') do
...
关于string - 以符合现有代码期望的方式迭代可能的空行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10416869/