如何从 Lua 中的字符串中删除最后一行?

How to remove last line from a string in Lua?

我在玩魔兽世界Lua

我有这个字符串:

"This\nis\nmy\nlife."

所以当打印时,输出是这样的:

This
is
my
life.

如何将除最后一行之外的整个字符串存储在新变量中?

所以我希望新变量的输出是这样的:

This
is
my

我希望 Lua 代码找到最后一行(不管字符串中有多少行),删除最后一行并将剩余行存储在新变量中。

谢谢。

#! /usr/bin/env lua

local serif = "Is this the\nreal life?\nIs this\njust fantasy?"
local reversed = serif :reverse()  --  flip it

local pos = reversed :find( '\n' ) +1  --  count backwards
local sans_serif = serif :sub( 1, -pos )  --  strip it

print( sans_serif )

如果你愿意,你可以联机,结果相同。

local str = "Is this the\nreal life?\nIs this\njust fantasy?"
print(  str :sub( 1,  -str :reverse() :find( '\n' ) -1 )  )

Is this the
real life?
Is this

最有效的解决方案是简单的 string.find。

local s = "This\nis\nmy\nlife." -- string with newlines
local s1 = "Thisismylife." -- string without newlines

local function RemoveLastLine(str)
    local pos = 0 -- start position
    while true do -- loop for searching newlines
        local nl = string.find(str, "\n", pos, true) -- find next newline, true indicates we use plain search, this speeds up on LuaJIT.
        if not nl then break end -- We didn't find any newline or no newlines left.
        pos = nl + 1 -- Save newline position, + 1 is necessary to avoid infinite loop of scanning the same newline, so we search for newlines __after__ this character
    end
    if pos == 0 then return str end -- If didn't find any newline, return original string

    return string.sub(str, 1, pos - 2) -- Return substring from the beginning of the string up to last newline (- 2 returns new string without the last newline itself
end

print(RemoveLastLine(s))
print(RemoveLastLine(s1))

请记住,这仅适用于具有 \n 样式换行符的字符串,如果您有 \n\r\r\n 更简单的解决方案是模式。

此解决方案对于 LuaJIT 和长字符串非常有效。 对于小字符串 string.sub(s1, 1, string.find(s1,"\n[^\n]*$") - 1) 很好(不是在 LuaJIT 上)。

所以我发现 Egor Skriptunoff 在评论中的解决方案确实非常有效,但我无法将他的评论标记为答案,所以我将他的答案放在这里。

这将删除最后一行并将剩余行存储在新变量中:

new_str = old_str:gsub("\n[^\n]*$", "")

如果在最后一行的末尾有一个新的行标记,Egor 发布了这个作为解决方案:

new_str = old_str:gsub("\n[^\n]*(\n?)$", "%1")

虽然这会删除第一行并将其余行存储在新变量中:

first_line = old_str:match("[^\n]*")

谢谢你的帮助,Egor。

我向后扫描它是因为向后扫描比向前扫描更容易从后面移除东西如果向前扫描会更复杂而向后扫描更简单

我一次成功

function removeLastLine(str) --It will return empty string when there just 1 line
  local letters = {}
  for let in string.gmatch(str, ".") do --Extract letter by letter to a table
    table.insert(letters, let)
  end

  local i = #letters --We're scanning backward
  while i >= 0 do --Scan from bacward
    if letters[i] == "\n" then
      letters[i] = nil
      break
    end
    letters[i] = nil --Remove letter from letters table
    i = i - 1
  end
  return table.concat(letters)
end

print("This\nis\nmy\nlife.")
print(removeLastLine("This\nis\nmy\nlife."))

代码的工作原理

  1. str参数中的字母将被提取到table("Hello"将变为{"H", "e", "l", "l", "o"}

  2. i local设置为table的末尾,因为我们是从后往前扫描的

  3. 检查 letters[i] 是否为 \n 如果换行则转到步骤 7

  4. 删除 letters[i]

    处的条目
  5. 减去i与1

  6. 转到第 3 步,直到 i 为零如果 i 为零,则转到第 8 步

  7. 删除 letters[i] 处的条目,因为它在检查换行符时尚未删除

  8. Returntable.concat(letters)。不会导致错误,因为如果 table 为空

    table.concat return 空字符串