Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Алгоритм преобразования адреса в формате эксела


Автор: Gunslinger 11.11.2008, 12:07
рекурсию?
Привет!
Формат адреса эксела, например: А18:G32. Нужно преобразовать буквы в цифры и разложить все по x1, y1 и, если необходимо, в x2,y2.
Мой вариант:
Код

   String Mass="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   int x1, y1;//адрес ячейки
   int x2, y2; //адрес второй ячейки - если 2 ячейки объединены
   String XlsAddr="A20:D17";//например
   
    size=XlsAddr.length();//длина адреса

   int i=k=n=1; //счетчики
   
   for(i;i<=size;i++) //проходим по каждому символу адреса
   {
         if(XlsAddr[i]!=":") //если символ до :, то помещаем адрес в x1,y1
                {
                     for(n;n<=size;n++) //парсим строку с алфавитом на соответствие
                     {
                        if(XlsAddr[i]==Mass[n]) x1=n; //если соответствие найдено - в х1 помещаем порядковый номер в алфавите
                              else y1=StrToInt(XlsAddr[i]); //иначе это не буква, а цифра - значит вторая координата - у1.
                      }
                  };
           else
                 {
                     for(k;k<=size;k++)//если двоеточие обнаружено - значит дальше идет второй адрес - x2,y2
                     {
                        if(XlsAddr[i]==Mass[k]) x2=k; //все тоже самое, только координаты для сохранения другие
                              else y2=StrToInt(XlsAddr[i]);
                      }
                  }
    };

Пока проверить возможности нет.

Добавлено через 4 минуты и 9 секунд
не заметил. если y состоит из 2х цифр, то они будут перезаписаны. Тогда у надо сначала складировать в стринг, а потом преобразовывать. В остальном как?

Автор: xvr 11.11.2008, 18:00
Все у тебя какое то буйство получается  smile 
Код


int eat_syms(const char* &str)
{
 int rv=0;
 for(;isalpha(*str);++str) rv=rv*26+toupper(*str)-'A';
 return rv;
}

int cvt_syms(const char* &str)
{
 const char* s=str;
 int rv=eat_syms(str);
 switch(str-s)
  {
    case 2: rv+=26; break;
    case 3: rv+=26*26+26; break;
  }
 return rv;
}

void cvt_addr(const char* &str, int& x, int& y)
{
 y=cvt_syms(str);
 x=strtoul(str,(char**)&str,10);
}


...
int x1, y1;//адрес ячейки
int x2, y2; //адрес второй ячейки - если 2 ячейки объединены
String XlsAddr="A20:D17";

const char* str=XlsAddr.c_str();
cvt_addr(str,x1,y2);
if (*str==':') cvt_addr(str,x2,y2);
...


Автор: Gunslinger 12.11.2008, 11:01
Исправил ошибки в коде - но алгоритм работает неправильно: х1=1, у1=7, х2=19, у2=7 при A20:D17
Буйство в смысле опять код косячный? Твой код слишком крут для моей неокрепшей психики - кроме ключевых слов ничего не понялsmile Объяни смысл своего алгоритма, я напишу. Проблема, мне кажется, в неправильном алгоритме.

Автор: xvr 12.11.2008, 14:58
Цитата(Gunslinger @ 12.11.2008,  11:01)
Буйство в смысле опять код косячный? 

В смысле не надо пытаться изобретать велосипеды, а надо пользоваться стандартными библиотеками, на то они и сделаны.

Цитата

Твой код слишком крут для моей неокрепшей психики - кроме ключевых слов ничего не понялsmile Объяни смысл своего алгоритма, я напишу.
Это уже готовый кусок программы (с небольшими ошибками  smile )

Код

int eat_syms(const char* &str)
{
 int rv=0;
 for(;isalpha(*str);++str) rv=rv*26+toupper(*str)-'A';
 return rv;
}
Функция сканирует поданную строку (str), все найденные в начале буквы трактует как число в позиционной системе счисления по оснаванию 26 (A - 0, B-1 и т.д.)
Возвращает что получилось, строку продвигает на первую не букву
Код

int cvt_syms(const char* &str)
{
 const char* s=str;
 int rv=eat_syms(str);
 switch(str-s)
  {
    case 2: rv+=26; break;
    case 3: rv+=26*26+26; break;
  }
 return rv+1;
}
Функция берет число, возвращенное предыдущей функцией, вычисляет длинну букв в начале и прибавляет сдвиг, т.к. 2х и 3х буквенные имена столбцов соотвествуют разным начальным столбцам (2х буквенные начинаются с 26го столбца, после последнего одно буквенного, 3х буквенные - после последнего 2х буквенного)
Код

void cvt_addr(const char* &str, int& x, int& y)
{
 y=cvt_syms(str);
 x=strtoul(str,(char**)&str,10);
}
Функция отгрызает от строки буквенный префикс и записывает его в y, потом отгрызает цисло, записывает его в x, str передвигается за число
Код

 cvt_addr(str,x1,y1);
 if (*str==':') cvt_addr(++str,x2,y2);
Вычисляется x1 & y1, затем проверяется, если первый необработанный символ ':', то он пропускается и все, что за ним записывается в x2 & y2

Автор: Gunslinger 12.11.2008, 20:06
 smile 
Пойду осмыслю...

Автор: YanTsys 13.11.2008, 14:00
А екселовские функции  ЧИСЛСТОЛБ , СТОЛБЕЦ, ЧСТРОК и СТРОКА прикрутить не пробовали?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)