Как удалить строки из строки, начинающейся с определенной строки в Lua?

Как удалить строки из строки, начинающейся с другой строки в Lua? Например, я хочу удалить всю строку из строки result, начинающейся со слова <Table. Это код, который я написал до сих пор:

for line in result:gmatch"<Table [^\n]*" do line = "" end

person Christos K.    schedule 06.10.2013    source источник
comment
Если вы разбираете HTML, не используйте lua-шаблоны. Попробуйте HTML-парсер   -  person hjpotter92    schedule 06.10.2013
comment
Это XML с пространствами имен, я использую Corona SDK.   -  person Christos K.    schedule 06.10.2013
comment
Наверное, не стоит использовать для этого шаблоны. Шаблоны Lua менее эффективны, чем регулярные выражения и регулярные выражения нельзя использовать для синтаксического анализа XHTML и Ко..   -  person Lorenzo Donati -- Codidact.com    schedule 06.10.2013
comment
Я рекомендую использовать настоящий xml для анализа входного файла. При манипулировании строками не принимаются во внимание & экранирование, <!-- комментарии, пробел < Table и т. Д. (Точно так же я также настоятельно рекомендую использовать инструмент, поддерживающий XML, для генерации вашего XML по тем же причинам).   -  person hugomg    schedule 07.10.2013
comment
Знаете ли вы какой-либо синтаксический анализатор xml для обработки такого рода xml (pastebin.com/embed_iframe.php?i = P3DxHB8x)? P.S. парсер должен работать с corona sdk.   -  person Christos K.    schedule 09.10.2013


Ответы (4)


string.gmtach используется для получения всех вхождений шаблона. Для замены определенного шаблона нужно использовать string.gsub.

Другая проблема заключается в том, что ваш шаблон <Table [^\n]* будет соответствовать всей строке, содержащей слово <Table, а не только начинаться с него.

Шаблон Lua не поддерживает привязку начала строки, это почти работает:

local str = result:gsub("\n<Table [^\n]*", "")

за исключением того, что он пропустит первую строку. Мое решение использует второй прогон для проверки первой строки:

local str1 = result:gsub("\n<Table [^\n]*", "")
local str2 = str1:gsub("^<Table [^\n]*\n", "")
person Yu Hao    schedule 06.10.2013
comment
@EgorSkriptunoff Ага, это умно и элегантно. - person Yu Hao; 07.10.2013
comment
Шаблон Lua поддерживает привязку начала строки. - person Alexander Altshuler; 08.10.2013
comment
@AlexanderAltshuler Какой ...? - person Yu Hao; 08.10.2013

Библиотека LPEG идеально подходит для такого рода задач. Просто напишите функцию для создания пользовательских стрипперов:

local mk_striplines
do
  local lpeg      = require "lpeg"
  local P         = lpeg.P
  local Cs        = lpeg.Cs
  local lpegmatch = lpeg.match

  local eol       = P"\n\r" + P"\r\n" + P"\n" + P"\t"
  local eof       = P(-1)
  local linerest  = (1 - eol)^1 * (eol + eof) + eol

  mk_striplines = function (pat)
    pat               = P (pat)
    local matchline   = pat * linerest
    local striplines  = Cs (((matchline / "") + linerest)^1)
    return function (str)
      return lpegmatch (striplines, str)
    end
  end
end

Обратите внимание, что аргумент mk_striplines() может быть строкой или шаблоном. Таким образом, результат получается очень гибким: mk_striplines (P"<Table" + P"</Table>") создаст стриппер, который отбрасывает линии с двумя разными шаблонами. mk_striplines (P"x" * P"y"^0) отбрасывает каждую строку, начиная с x, за которым следует любое количество y - вы поняли.

Пример использования:

local linestripper = mk_striplines "foo"

local test = [[
foo lorem ipsum
bar baz
buzz
foo bar
xyzzy
]]

print (linestripper (test))
person Philipp Gesang    schedule 06.10.2013

Другие ответы предоставляют хорошие решения для фактического удаления строк из строки, но не объясняют, почему ваш код этого не делает.

Переформатировав для наглядности, вы написали:

for line in result:gmatch"<Table [^\n]*" do 
    line = "" 
end

Первая часть - разумный способ перебрать result и извлечь все отрезки текста, которые начинаются с <Table и продолжаются до следующего символа новой строки, но не включая его. Итератор, возвращаемый gmatch, возвращает копию совпадающего текста при каждом вызове, а локальная переменная line содержит эту копию для тела цикла for.

Поскольку соответствующий текст копируется в line, изменения, внесенные в line, не изменяют и не могут изменять фактический текст, хранящийся в result.

Это связано с более фундаментальным свойством строк Lua. Все строки в Lua неизменяемы. После сохранения они не могут быть изменены. Переменные, содержащие строки, фактически содержат указатель на внутреннюю таблицу неизменяемых строк с подсчетом ссылок, которая допускает только две операции: интернализацию новой строки и удаление интернализованной строки без оставшихся ссылок.

Таким образом, любой подход к редактированию содержимого строки, хранящейся в result, потребует создания совершенно новой строки. Если string.gmatch обеспечивает итерацию по содержимому, но не позволяет его изменять, string.gsub обеспечивает создание новой строки, в которой весь текст, соответствующий шаблону, был заменен чем-то новым. Но даже string.gsub не меняет неизменный исходный текст; он создает новую неизменяемую строку, которая является копией старой с выполненными заменами.

Использование gsub может быть таким простым:

result = result:gsub("<Table [^\n]*", "")

но это выявит другие дефекты самого рисунка. Во-первых, и это наиболее очевидно, ничто не требует, чтобы шаблон совпадал только с началом строки. Во-вторых, шаблон не включает новую строку, поэтому строка останется пустой.

Все это можно улучшить, осторожно и грамотно используя библиотеку шаблонов. Но это не меняет того факта, что вы начинаете с текста XML и не обрабатываете его с помощью инструментов, поддерживающих XML. В этом случае любой подход, основанный на сопоставлении с образцом или даже на регулярных выражениях, скорее всего, закончится плачевно.

person RBerteig    schedule 07.10.2013
comment
Очень полезный ответ, можете ли вы предложить мне синтаксический анализатор xml в lua для обработки таких файлов xml (pastebin .com / embed_iframe.php? i = P3DxHB8x)? Парсер XML не должен использовать файлы dll, потому что я хочу использовать его для corona sdk. - person Christos K.; 09.10.2013
comment
См. Wiki пользователя Lua, где есть страница, посвященная синтаксическим анализаторам XML для Lua. Есть несколько чистых решений Lua и несколько, которые связывают внешние библиотеки. Тем не менее, я был бы склонен ожидать, что уже существует хорошо известный синтаксический анализатор XML как часть или обычно используется с Corona, но не будучи пользователем Corona, я не знаю, что это такое. - person RBerteig; 10.10.2013

result = result:gsub('%f[^\n%z]<Table [^\n]*', '')

Начало этого шаблона, '%f[^\n%z], является шаблоном границы, который будет соответствовать любому переходу от символа новой строки или нулевого символа к другому символу, а для шаблонов границ предшествующий первый символ считается нулевым символом. Другими словами, использование этого префикса позволяет остальной части шаблона совпадать либо с первой строкой, либо с любым другим началом строки.

Ссылка: руководство по Lua 5.3, раздел 6.4.1 о строковых шаблонах

person Tyler    schedule 09.11.2015