2

我曾经用一个简单的方法迭代字符串中的行

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) 可以输出它作为额外的好处,那将特别棒。

4

1 回答 1

2

如果您需要准确检测换行符边界而不是跳过/丢弃它们,以跨平台方式,您不能使用同时包含\rand的集合\n,因为它将匹配换行符序列\r\n两次而不是一次(CRLF 是单个换行符在 DOS/Windows 上)。你可以使用足够强大的正则表达式引擎(例如支持交替)来处理这个问题,但是 Lua 的模式匹配库非常少。

最好的办法是在处理文本之前规范化换行符,如下所示:

function normalize_eols(s)
    return s
        :gsub('\r\n','\n')
        :gsub('\r', '\n')
end

至于您的 input=>output 网格,如果我们将换行符视为行分隔符,那么我希望[^\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
    ...
于 2012-05-02T19:53:24.207 回答