以符合现有代码期望的方式遍历可能为空的行。

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

for line in s:gmatch("[^\r\n]+") do

这个方法非常完美!然后,现实生活发生了......

....现在我的需求已经改变了:我也需要匹配空行。这里就出现问题了:由于这种迭代形式用于多个不同的位置,而且每个位置都有其自身的复杂性,所以我希望尽可能避免更改周围的代码。我的 gmatch/ find 尝试一直无法创建上述模式的“可替换”版本,因为这些函数有微妙的期望无法匹配。

我需要的语句( for line in some_matcher(s) do)符合以下要求,我相信这些要求包括我所担心的所有边缘情况:

   输入            期望

1. ''            -- 匹配一次   ('')
2. '\r\n'        -- 匹配两次  ('', '')
3. '\r\n\r\n'    -- 匹配三次 ('', '', '')
4. 'aaa'         -- 匹配一次   ('aaa')
5. 'aaa\r\n'     -- 匹配两次  ('aaa', '')
6. 'aaa\r\nbbb'  -- 匹配两次  ('aaa', 'bbb')
7. '\r\nbbb'     -- 匹配两次  ('', 'bbb')

我的老方法假设只有 \r\n 行尾发生,如果新方法只处理该场景,那么完全没问题。

然而,由于我公司计划支持 Linux,如果答案还处理更直观的 \n 行尾(为了未来使用),那将非常感激,并且可以避免在几个月后重访此问题。但是,限制是在许多情况下,我需要该匹配项在原始字符串输入中的起始列。如果上述语句( for ... do)可以作为附加功能输出,那会非常棒。

原文链接 https://stackoverflow.com/questions/10416869

点赞
stackoverflow用户501459
stackoverflow用户501459

如果你需要准确地检测换行符边界而不是跳过/丢弃它们,以跨平台的方式来说,你不能使用一个包括\r\n的集合,因为它会将换行符\r\n匹配两次而不是一次(在DOS/Windows上,CRLF是一个单独的换行符)。你可以使用功能强大的正则表达式引擎(例如支持交替的引擎)来处理这个问题,但 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
    ...
2012-05-02 19:53:24