Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Парсинг переменной String


Парсинг переменной String

Сообщений 1 страница 7 из 7

1

Приветствую. Пишу эмулятор мелодий древних нокиа. Все понятно и вразумительно. Мелодий куча. Они следующего формата:
4e2 8b1 4e2 4#f2 8g2 4a2 8.g2 4#f2 4e2 8d2 1c2 1&d2 4e2 8b1 4e2 4#f2 8g2 4a2 8g2 4#f2 4e2 8#f2 1g2 1a2 4- 4b2 8#g2 4a2 8b2 4c3 8a2 4.e2 8g2 2#f2 32- 8#f2 8d3 8c3 1b2 4- 4a2 8#f2 4g2 8a2 4c3 8b2 4#d3 8b2 8a2 8#f2

Данные собираюсь разделить запятыми и потом разложить по длительности и частотам. В этом собственно и загвоздка возникла.
Чтоб не пинали - вот хрень которая получается, но не то это все. Подскажите алгоритм как парсить на примере '"4.#g2" "4.e2" , "8-" , "16#g2", "32d3"
На выходе нужно от двух до 4х переменных 4, ., #g2 и т.д Еще думаю может проще проверять присутствие тех или иных нот и символов и сравнивать с таблицей?
Вот таблица всех возможных нот
Data "c1" , "#c1" , "d1" , "#d1" , "e1" , "f1" , "#f1" , "g1" , "#g1" , "a1" , "b1" , "h1" , "c2" , "#c2" , "d2" , "#d2" , "e2" , "f2" , "#f2" , "g2" , "#g2" , "a2" , "b2" , "h2" , "c3" , "#c3" , "d3" , "#d3" , "e3" , "f3" , "#f3" , "g3" , "#g3" , "a3" , "b3" , "h3" , "c4" , "#c4" , "d4" , "#d4" , "e4" , "f4" , "#f4" , "g4" , "#g4" , "a4" , "b4" , "h4" , "c5" , "#c5" , "d5" , "#d5" , "e5"

Код:
$regfile = "m8def.dat"
$crystal = 8000000
$baud = 9600                                                ' use baud rate  тут несколько строк по настройке UART
$hwstack = 32                                               ' default use 32 for the hardware stack
$swstack = 10                                               ' default use 10 for the SW stack
$framesize = 40
Dim Instring As String * 10 , Левый_символ As String * 1 , Октава As String * 1 , Нота As String * 2 , Длинна_строки As Byte , Есть_символ As Byte , I As Byte , I_string As String * 2 , Длинна_ноты As Integer , Диез As Bit , Частота As Integer
Instring = "16#g2"                                          '"4g2" "4.e2" , "8-" , "16#g2", "32d3"



Instring = Trim(instring) : Instring = Lcase(instring)      ' обрезаем пробелы в начале и конце строки если они есть,  переводим строку в нижний регистр
Длинна_строки = Len(instring)                               ' узнаем длинну строки
Длинна_ноты = Val(instring)                                 ' переводим первые два символа в число
Октава = Right(instring , 1)
If Октава = "-" Then : Октава = "0" : Else : Нота = Right(instring , 2) : End If







If Длинна_ноты < 10 And Длинна_ноты <> 0 Then : Decr Длинна_строки : Instring = Right(instring , Длинна_строки) : Elseif Длинна_ноты <> 0 Then : Длинна_строки = Длинна_строки - 2 : Instring = Right(instring , Длинна_строки) : End If       ' вырезаем первые цыфры
Левый_символ = Left(instring , 1)

If Левый_символ = "#" Then : Set Диез : Decr Длинна_строки : Instring = Right(instring , Длинна_строки) : Else : Reset Диез : End If
If Левый_символ = "." Then : Длинна_ноты = Длинна_ноты * 15 : Длинна_ноты = Длинна_ноты / 10 : End If       ' звучание ноты в 1,5 раза дольше
If Левый_символ = ";" Then Длинна_ноты = Длинна_ноты * 2
If Левый_символ = "&" Then : Длинна_ноты = Длинна_ноты * 25 : Длинна_ноты = Длинна_ноты / 10 : End If       ' звучание ноты в 2,5 раза дольше
If Левый_символ = "-" Then Print "пауза"


If Длинна_строки > 1 Then
  Decr Длинна_строки : Instring = Right(instring , Длинна_строки)
  If Левый_символ = "c" Then Частота = 1
  If Левый_символ = "d" Then Частота = 3
  If Левый_символ = "e" Then Частота = 5
  If Левый_символ = "f" Then Частота = 6
  If Левый_символ = "g" Then Частота = 8
  If Левый_символ = "a" Then Частота = 10
  If Левый_символ = "b" Then Частота = 11
  If Левый_символ = "h" Then Частота = 12
  If Диез = 1 Then Incr Частота
End If


Print "Нота = " ; Нота
Print "Длинна ноты = " ; Длинна_ноты
Print "Частота = " ; Частота
'Print "Осталось = " ; Instring
Print "октава = " ; Октава
End

сами цифры означают следующее:
4#g2 - длинна ноты 1/4, нота g ( до диез) вторая октава.
8-  это пауза 1/8 длинны ноты
4.e2 точка означает что длительность 1/4 нужно умножить на 1.5 вместо точки могут быть ; &

0

2

Ну делайте разделитель к примеру #0D в конце каждой ноты.

0

3

Не понял. Поподробнее пожалуйста напишите. Есть готовые мелодии https://vk.com/topic-96676_22391837 максимум какой с ними придется делать это заменить пробел на " , " чтоб норм разделение в Data было.
Переспав с мыслью решил поступить так:
Берем первый код звука из таблицы
Melody1:
Data "8e2" , "4g2" , "4-" , "8g2"
Берем первую ноту Nota:
Nota:
Data "#c1" , "c1" , "#d1" , "d1" , "e2" , "f1" ......

Проверяем код звука на присутствие каждой ноты. Ищем #с1 в 8e2 потом с1, потом #d1.....  При совпадении получаем порядковый номер ноты (в примере это 4) потом возьмем из другой таблицы частоту звучания. И так для каждого кода.
Время звучания, которое в 8e2 равно 1/8 берем так:
Длинна_ноты = Val(код_звука) 'Длинна_ноты As Integer
Остается проверить каждый код на наличие точк ; - $. И соответственно умножить время звучания на коэффициент скрытый в этих символах. Проверка такая же как и на наличие нот.

Теперь мы знаем время проигрывания и частоту. Делаем генерацию частоты таймером 1.
Данный код хорош тем что даже если в коде ноты будут ошибки - они пропустятся т.к. все остальные символы мы игнорируем а точнее их не ищем.

Не понял что означает код звука к примеру 8-1. "8-" это пауза с длинной 1/8 что такое "1" - хз. К примеру "с1" это нота с первой октавы. Но не может же быть тишины первой октавы))))) Так что для моего алгоритма "8-1" и "8-" выглядят одинаково.

Вот часть которая выделяет первое число и ноту, допилю еще знаки припенания:

Код:
Кол_во_звуков_мелодии = Lookup(0 , Melody1)

For Номер_звука = 1 To Кол_во_звуков_мелодии                ' перебираем коды звука поочереди в переменную "Код_звука"
     Код_звука = Lookupstr(номер_звука , Melody1)

      For I = 0 To 52                                       ' Находим Ноты В "Код_звука" Которые Перебираются Из "Nota:" Всего возможных нот 53
           Нота = Lookupstr(i , Nota)
           Есть_нота = Instr(код_звука , Нота)              ' Проверяем переменную "Код_звука" на присутствие ноты
           If Есть_нота <> 0 Then Exit For                  '  Если нота присутствует то выходим из цикла. Порядковый номер ноты сохранен в переменной I. Когда ноты нет I = 53
      Next
Длинна_ноты = Val(код_звука)                                ' Берем первое число из кода звука. Для 8е2 это 8.

Еще вопрос как проверить к примеру первый символ строковой переменной на то число это или что-то другое? Наверное смотреть кодировку ASCII и если символ в диапазоне &#048-&#057 то это число?

Отредактировано Pasha (2017-01-04 17:58:46)

0

4

Можно вообще не париться и сделать разделитель прямо как там - пробел.
Запихивайте всю мелодию сразу строкой, конец всей мелодии сам определится.
Перед тем как начать делать движок обработки мелодий, сделайте тестовый парсер/тест строк, чтобы можно было понять о правильности его работы (пусть в порт TX выдает по строке каждую ноту).
Читайте всё MID-ом, а длину определяйте LEN.

0

5

Хороший совет. И тут появляется ограничение строковой переменной в 255 символов. Как читать строку длиннее? Прикинул и получается что мне нужна строка на 600 символов.
В голову пришла только идея разбить мелодию на куски по 255 символов и загружать по очереди и разбирать.

Можно как то посчитать сколько ячеек в таблице?
К примеру тут 5 ячеек:

Код:
Melody:                                                     ' мелодия должна быть разбита на строки с количеством символов до 255 включительно
Data 3                                                      ' Количество строк c мелодией Data (ячеек таблицы)
Data 240                                                    ' Темп мелодии
Data "8a2 16#g2 16- 8#g2 8- 8a2 16#g2 16- 8#g2 8- 8a2 16#g2 16- 4#g2 8.e3 4- 16- 8e3 16#d3 16- 8#c3 8- 8#c3 16b2 16- 8a2 8- 16.a2 32- 16#g2 16- 8#f2 8- 8#f2 4- 8- 16.#g2 32- 16.#f2 32- 8#f2 8- 8#g2 16#f2 16- 8#f2 8- 8#g2 16#f2 16- 4#f2 8#d3 4- 8- 8#d3 8#c3 8c3"
Data "8- 8c3 8a2 16.#g2 8- 32- 8#g2 8#f2 8e2 8- 8e2 4- 8- 8e3 16#d3 16- 4#d3 4#f3 4c3 4#d3 4#c3 4#g2 4- 16.e3 32- 16#d3 16- 4#d3 4#f3 4c3 4#d3 4#c3 4e3 8#d3 8#c3 8b2 8a2 1#g2 1g2 2#g2 4- 16#g1 16- 16#g1 16- 2#g1 4- 16#g1 16- 16#g1 16- 2#g1 4- 16#g1 16- 16#g1"
Data "16- 8#g1 8- 16#g1 16- 16#g1 16- 8#g1 8- 16#g1 16- 16#g1 16- 2#g1"

0

6

Вообще есть такая штука: http://avrhelp.mcselec.com/index.html?bigstrings.htm

0

7

А не лучше было бы пересчитать все в три таблицы в екселе и в программу положить не строковые переменные, а byte,word?

Частота
Длительность
Пауза

+1


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Парсинг переменной String