Технический форум по робототехнике.
redcat » 01 фев 2009, 13:40
Вот вчера понадобилось измассива символов (строки) выделить один или два фрагмента разделяемых символами конца строки и переноса каретки (\r\n) в другие два массива. Что у меня получилось, привожу ниже. Всё работает. Меня интересуют другие варианты подобного фильтрования, но без использования стандартных функций (типа trim(), length()), всё должно компилироваться для микроконтроллера, например на WinAVR.
- Код: Выделить всё • Развернуть
#include <stdlib.h> // Если не вписать..
#define F_CPU 4 // ...эти две строки
//то на форуме код будет отображаться криво (скрипт не видит что это Код СИ)
char buffer[] = "\r\nMEMORY_FULL\r\n\r\nERROR\r\n"; //Строка в буффере из которой
//нужно получить состояние (сейчас это будет "ERROR")
//и описание состояния (сейчас это описание ошибки "MEMORY_FULL")
char info1[32]; // Сюда нужно поместить описание состояния
//(в конце программы тот должно быть "MEMORY_FULL"
char status1[10];// Сюда нужно поместить состояние
//(в конце программы тот должно быть "ERROR"
////////////////////////////////
void filtr(char *tmpch){ //Функция ФИЛЬТР, в неё передаём массив который нужно отфильтровать
int ind=0;
intcc=0;
int*m; // указатель для my_memo[]
intmy_memo[4]={-1,-1,-1,-1}; //Хранилище номеров первого и последнего символа для каждого слова в массиве
char *s;
m=&my_memo[0]; // Указываем на адрес первой ячейки в массиве
while(*tmpch){ //перебираем массив buffer[]
if((*tmpch != '\r')&&(*tmpch != '\n')&&(*tmpch != '\0')){ //Если текущий символ не \0 \r \n
if(ind==0){ *m++=cc; ind=1;} // и если он первый то добавляем
//его порядковый номер в my_memo[]
//устанавливаем ind=1; Пока ind=1 то в my_memo[0] ничего не записываем
}else{
//Если это любой символ из \0 \r \n
if(ind==1){ *m++ = (cc-1); } // И если в my_memo[] была запись номера первого символа
// Записываем в следующую ячейку my_memo[] номер последнего символа слова
//(фактически это номер первого символа разделителя \r минус 1)
ind=0; // разрешаем новую запись в my_memo[] если попадается символ слова
}
cc++; // Инкреминируем порядковый номер символа в buffer[]
*tmpch++; //перемещаем указатель
}
if(ind==1){ *m=cc-1; } // Если последний символ слова не отмечен
//(в случае когда в конце строки в буффере нет символов разделителей \r\n)
////////////
// заполняем массивы info1[] status1[] в зависимости от номеров в my_memo[]
if(my_memo[0]!=-1 && my_memo[1]!=-1 && my_memo[2]!=-1 && my_memo[3]!=-1 ){
//Если my_memo[] заполнен полностью, т.е есть и состояние и описание
cc=0;
for (int tmp=my_memo[2];tmp<=my_memo[3];tmp++){
status1[cc++]=rx_buffer[tmp];
}
cc=0;
for (int tmp=my_memo[0];tmp<=my_memo[1];tmp++){
info1[cc++]=rx_buffer[tmp];
}
}else if(my_memo[0]!=-1 && my_memo[1]!=-1){// если в my_memo[] "координаты" только одного слова из строки
//т.е. состояние без его описания (например buffer[] = "READY\r\n";)
cc=0;
for (int tmp=my_memo[0];tmp<=my_memo[1];tmp++){
status1[cc++]=rx_buffer[tmp];
}
}
int main(void){
filtr(buffer);
//После вызова функции массивы info1 и status1 содержат
//info1[] = MEMORY_FULL
//status1[] = ERROR
buffer[] = "READY\r\n"; // меняем строку в буффере
filtr(buffer);
//После вызова функции массивы info1 и status1 содержат
//info1[] = "";
//status1[] = READY
}
В общем может ктото предложит другое решение, или оптимизирует это???!!!
Сергей » 01 фев 2009, 13:57
Извини, но это фарш какойто, приведи код в порядок.
redcat » 01 фев 2009, 14:02
Тут трудно красиво код показать. Все табы и лишние пробелы удаляются.
сам код я как смог прокомментировал.
Сергей » 01 фев 2009, 14:05
- Код: Выделить всё • Развернуть
if(ind==0){ *m++=cc; ind=1;}
Вот это что за шняга? Или ты думаешь что каждый раз должны перечитывать весь код, чтобы вспомнить что это за переменные? Ну ладно с табами здесь никак, но уж нормально назвать переменные стоило бы
redcat » 01 фев 2009, 14:11
Насчёт названий переменных, это да....
Попробую переписать.
Сергей » 01 фев 2009, 14:14
Найти в инете книгу "С++ для профессионалов. Н.Солтер, С.Клепер", там почитай главу 7 "Кодируем стильно".
=DeaD= » 01 фев 2009, 14:19
Ничего не понял - есть строка с разделителями \n\r и надо из неё извлечь первые 1-2 построки разделённые этими разделителями или как?
Добавлено спустя 4 минуты 7 секунд:
Если да, тогда заведи переменную status=0 и пробегись по строке, меняя статус от текущего символа c[i] каждый раз по правилу:
c[i]=="\n" => status=1
c[i]=="\r" && status==1 => status=2
else => status=0
Если статус=2, тогда можно считать что только что было \n\r и можно либо сразу скопировать подстроку новую, либо записать её начало и конец.
Сергей » 01 фев 2009, 14:20
Кстати, если говорить о самом коде, где аффтор хочет выделять коды ошибок, - лучше использовать
- Код: Выделить всё • Развернуть
const char *errors[] =
{
"ERROR 0",
"ERROR 1",
"ERROR 2",
NULL
}
А потом обращаца по номеру ошибки, чтобы получить ее строковый эквивалент
типа
- Код: Выделить всё • Развернуть
char *string = string_new( errors[1] );
redcat » 01 фев 2009, 14:33
Вся гадость этой фильтрации в том, что символы \r и \n могут появлятся в фильтруемой строке по разному. И количество слов в строке может быть 1 или 2. Например возможны такие варианты строк -
\r\n1234567890\r\n\r\nERROR\r\n
1234567890\r\n\r\nERROR\r\n
1234567890\r\nERROR\r\n
1234567890\r\nERROR
\r\nERROR\r\n
ERROR\r\n
Вот из этих вариантов нужно выделить в массивы 1234567890 и ERROR
или только ERROR, как в двух последних строках.
Моя функция работает. Но чтото мне она не нравится.
Сергей » 01 фев 2009, 14:58
Погодь с фильтром, а собсно зачем тебе эта функция? Чем тебе мой вариант не подходит?
=DeaD= » 01 фев 2009, 15:08
redcat писал(а):\r\n1234567890\r\n\r\nERROR\r\n
Строго говоря в этой строке 5 слов, разделённые \r\n: пустое, "1234567890", пустое, "ERROR, пустое.
Добавлено спустя 5 минут 11 секунд:Пусть c[i] - строка, которую разбираем.
i=1; start=0;
if(c[0]!=0)while(c[i]!=0){
if(c[i-1]=='\r' && c[i]=='\n'){
if(i>start+1){ нашли очередное слово c[start..i-2] };
start=i+1;
};
};
redcat » 01 фев 2009, 16:48
Сейчас попробую развить...
Плохо то, что RAM всего 128 байт
Сергей » 01 фев 2009, 17:58
128 байт? это что за камень такой?
redcat » 01 фев 2009, 18:34
Сергей писал(а):128 байт? это что за камень такой?
))) Это камушек Attiny2313. Под рукой другого нету.
Вот что получилось -
- Код: Выделить всё • Развернуть
char MyString[32]="SYSTEM NOT READY\r\n\r\nERROR\r\n";
int SubStringStart = 0;
int SubStringEnd = 0;
int ItemCounter = 0;
while(MyString[ItemCounter]!=0){
if(MyString[ItemCounter]=='\r' && MyString[(ItemCounter+1)]=='\n' ){
SubStringEnd = (ItemCounter-1);
if(SubStringEnd>SubStringStart){
//Берём нужные данные из массива MyString от SubStringStart до SubStringEnd
;
// -------------------------
}
ItemCounter = ItemCounter+2 ;
SubStringStart = ItemCounter;
} else ItemCounter++;
Плохо только то, что в конце каждой подстроки должны быть \r\n