Lua Разделить строку по корневой ноте и названию аккорда

Мне нужно разделить множество названий аккордов на тональность и тип аккорда:

name = C
name = C#
name = Db
name = C#maj7b5
name = Cmaj7b5
name = Dbmaj7b5

поэтому корень всегда будет буквой сам по себе или с # или b, буквой сам по себе или только с # или b, корень должен будет = maj по умолчанию.

root = C
chord = maj
root = C#
chord = maj
root = Db
chord = maj
root = C#
chord = maj7b5
root = C
chord = maj7b5
root = Db
chord = maj7b5

Я могу получить корневое имя:

name1 = string.match(name, "%a#") 
name2 = string.match(name, "%ab") 
name3 = string.match(name, "%a")

если я получу нулевое значение в name1 и name2, то root = name3. Просто нужно название аккорда также.

РЕДАКТИРОВАТЬ: используется:

chord, pos = nil, 0
chord, p = string.match(region_name, "=%s+([^\n]+)()", pos)
if not p then end
pos = p
root, chord = string.match(region_name, "(%w[#b]?)(.*)$")
if not chord or #chord == 0 then chord = "maj" end

person LuaStart    schedule 29.01.2018    source источник


Ответы (1)


#!/usr/bin/env luajit

local text = [[
   name = C
   name = C#
   name = Db
   name = C#maj7b5
   name = Cmaj7b5
   name = Dbmaj7b5
]]

local chord, pos = nil, 0
while true do
   local chord, p = text:match("=%s+([^\n]+)()", pos) 
   if not p then break end
   pos = p
   local root, chord = chord:match("(%w[#b]?)(.*)$")
   if not chord or #chord == 0 then chord = "maj" end
   print(("root = %s"):format(root))
   print(("chord = %s"):format(chord))
end

Объяснение:

Сложность задачи заключается в поиске правильных регулярных выражений.

В первом регулярном выражении:

text:match("=%s+([^\n]+)()", pos) 

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

Теперь у вас есть аккорд, вы разделяете его на два элемента:

chord:match("(%w[#b]?)(.*)$")

Первые части получают одну букву (%w), а затем символы '#' или 'b', которые помечены как необязательные (?). Другая часть выражения получает любые символы (.*) до конца строки.

person Diego Pino    schedule 29.01.2018
comment
Спасибо, списка названий аккордов нет, это просто из другой функции chord_name, поэтому у него не будет списка: 'local text = [[ name = C name = C# name = Db name = C#maj7b5 name = Cmaj7b5 name = Dbmaj7b5 ]]' строка имя_аккорда - person LuaStart; 30.01.2018
comment
Итак, в этом случае я полагаю, что вас больше всего интересует тело цикла. Просто возьмите наиболее интересные для вас фрагменты и вставьте их в свой сценарий. OTOH, если ответ сработал для вас, не могли бы вы пометить его как принятый? meta.stackexchange.com/questions/ 5234/ - person Diego Pino; 30.01.2018
comment
Почему %w? Должно быть %u или [A-G]: "([A-G][#b]?)(%S*)" - person Egor Skriptunoff; 30.01.2018
comment
Верно, %w — это более широкое соответствие (буквенно-цифровое), а [A-G] соответствует только буквам аккордов. - person Diego Pino; 30.01.2018
comment
Спасибо, это должно сработать, у меня просто возникли проблемы с тем, как использовать его с local retval_region, _, region_pos, region_end, region_name, region_index, region_color = reaper.EnumProjectMarkers3(0, region_id), поскольку он получает его из вызова функции, а не из таблицы, он получает имя аккорда из region_name, это API в Reaper DAW. Последний ответ был обрезан, так как я должен помнить, что нельзя нажимать клавишу ввода для новой строки, поскольку она публикует ответ, если вы не отредактируете его через 5 минут, которые вы выкинули. - person LuaStart; 30.01.2018
comment
Технически (лучший вид) это шаблоны Lua, а не регулярные выражения. - person William Walsh; 01.02.2018
comment
Спасибо, использовал: chord, pos = nil, 0 chord, p = string.match(region_name, "=%s+([^\n]+)()", pos) if not p then end pos = p root, chord = string.match(region_name, "(%w[#b]?)(.*)$") if not chord or #chord == 0 then chord = "maj" end - person LuaStart; 01.02.2018