Intereting Posts
В чем разница между unsigned int и подписанным int в C? выделение массива внутри функции ac Почему pow (-infinity, positive non-integer) + бесконечность? Импорт PKCS12 с использованием SecItemImport Проблемы с Makefile – фатальная ошибка в читателе Использование stdlib.h в драйвере устройства Расположение указателей и глобальных переменных в C Требуется ли ключевое слово `struct` для объявления переменной структуры? Как рассчитать расстояние между координатами GPS на процессоре с плохой поддержкой с плавающей запятой? Создайте среду сборки для проекта «C» для динамического выбора папок во время компиляции Есть ли бит-эквивалент sizeof () в C? Отладка программы, которая сбрасывается 10 раз в разных местах возможная уязвимость переполнения буфера для va_list в C? Как дочерний процесс, как узнать, какой файловый дескриптор является родителем Создание массива в C и передача указателя на указанный массив для работы

метод для расширения az до abc … xyz form

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

например

az или 0-9 или abc или a-z0-9

дольше писать

например

abc … xyz или 0123456789 или abc или abcdefghijklmnouprstwxyz0123456789

1-я краткая кратчайшая запись = 1-й пример результата, который должен дать 🙂

до сих пор я пишу что-то вроде этого, и это работает только для писем от a до z:

expand(char s[]) { int i,n,c; n=c=0; int len = strlen(s); for(i = 1;s[i] > '0' && s[i]= 'a' && s[i] <= 'z' || s[i]=='-';i++) { /*c = s[i-1]; g = s[i]; n = s[i+1];*/ if( s[0] == '-') printf("%c",s[0]); else if(s[i] == '-') { if(s[i-1]<s[i+1]) { while(s[i-1] <= s[i+1]) { printf("%c", s[i-1]); s[i-1]++; } } else if(s[i-1] == s[i+1]) printf("%c",s[i]); else if(s[i+1] != '-') printf("%c",s[i]); else if(s[i-1] != '-') printf("%c",s[i]); } else if(s[i] == s[i+1]) { while(s[i] == s[i+1]) { printf("%c",s[i]); s[i]++; } } else if( s[len] == '-') printf("%c",s[len]); } 

}

но теперь я застрял 🙁

любые идеи, что я должен проверить, чтобы моя программа работала правильно?

Edit1: @Andrew Kozak (1) abcd (2) 01234

Спасибо за продвижение 🙂

Вот версия C ( примерно 38 эффективных строк ), которая удовлетворяет тому же тесту, что и моя предыдущая версия на C ++.

Полная тестовая программа, включающая ваши тестовые примеры, мои и некоторые испытания пыток, можно увидеть в прямом эфире на http://ideone.com/sXM7b#info_3915048

обоснование

Я почти уверен, что переоцениваю требования, но

  • это должно стать отличным примером того, как сделать синтаксический анализ надежным способом
    • использовать состояния в явном виде
    • подтвердить ввод (!)
      • эта версия не предполагает, что acb не может произойти
      • Он также не задушит или даже не сработает при простом вводе, например «Hello World» (или (char*) 0 )
  • он показывает, как вы можете избежать printf("%c", c) каждый символ без использования посторонних функций.
  • Я добавил несколько комментариев, чтобы объяснить, что происходит, но в целом вы обнаружите, что код в любом случае гораздо более parsingчив,

    • избегая слишком многих короткозначных переменных
    • избегая сложных условностей с непрозрачными индексаторами
    • избегая целого бизнеса длины строки. Нам нужен только макс. lookahead из 2 символов, а *it=='-' или predicate(*it) просто вернет false, если это нулевой символ. Оценка ярлыков не позволяет нам получить доступ к сквозным входным символам
  • ОДНА оговорка: я не выполнил надлежащую проверку переполнения выходного буфера (емкость жестко запрограммирована в 2048 символах). Я оставлю это как пресловутое упражнение для читателя

И последнее, но не менее важное: причина, по которой я это сделал :

  • Это позволит мне сравнить сырую производительность версии C ++ и этой версии C, теперь, когда они выполняют эквивалентные функции. Прямо сейчас я полностью ожидаю, что версия C превзойдет C ++ каким-то фактором (предположим: 4x?), Но, опять же, давайте просто посмотрим, что удивляет компиляторы GNU для нас. Позже обновление оказалось не за горами: github (code + results)

Реализация чистого C

Без дальнейших церемоний реализация, включая тестовый файл:

 #include  #include  #include  int alpha_range(char c) { return (c>='a') && (c<='z'); } int digit_range(char c) { return (c>='0') && (c<='9'); } char* expand(const char* s) { char buf[2048]; const char* in = s; char* out = buf; // parser state int (*predicate)(char) = 0; // either: NULL (free state), alpha_range (in alphabetic range), digit_range (in digit range) char lower=0,upper=0; // tracks lower and upper bound of character ranges in the range parsing states // init *out = 0; while (*in) { if (!predicate) { // free parsing state if (alpha_range(*in) && (in[1] == '-') && alpha_range(in[2])) { lower = upper = *in++; predicate = &alpha_range; } else if (digit_range(*in) && (in[1] == '-') && digit_range(in[2])) { lower = upper = *in++; predicate = &digit_range; } else *out++ = *in; } else { // in a range if (*in < lower) lower = *in; if (*in > upper) upper = *in; if (in[1] == '-' && predicate(in[2])) in++; // more coming else { // end of range mode, dump expansion char c; for (c=lower; c<=upper; *out++ = c++); predicate = 0; } } in++; } *out = 0; // null-terminate buf return strdup(buf); } void dotest(const char* const input) { char* ex = expand(input); printf("input : '%s'\noutput: '%s'\n\n", input, ex); if (ex) free(ex); } int main (int argc, char *argv[]) { dotest("az or 0-9 or abc or a-z0-9"); // from the original post dotest("This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6"); // from my C++ answer dotest("-xs a-9 9- ak-9 9-ac-7-3"); // assorted torture tests return 0; } 

Выход теста:

 input : 'az or 0-9 or abc or a-z0-9' output: 'abcdefghijklmnopqrstuvwxyz or 0123456789 or abc or abcdefghijklmnopqrstuvwxyz0123456789' input : 'This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6' output: 'This is some efghijklmnopqrstuvwxyz test in 567 steps; this works: abc. This works too: bcdefghijk. Likewise 45678' input : '-xs a-9 9- ak-9 9-ac-7-3' output: '-stuvwx a-9 9- abcdefghijk-9 9-abc-34567' 

Хорошо, я протестировал вашу программу и, похоже, работает практически в каждом случае. Он правильно расширяет az и другие разложения только с двумя буквами / числами. Он терпит неудачу, когда появляется больше букв и цифр. Исправить легко, просто создайте новый символ, чтобы сохранить последний печатный символ, если текущий печатный символ соответствует последнему, пропустите его. Сценарий a-z0-9 не работал, потому что вы забыли как [i]> = ‘0’ вместо s [i]> ‘0’. код:

 #include  #include  void expand(char s[]) { int i,g,n,c,l; n=c=0; int len = strlen(s); for(i = 1;s[i] >= '0' && s[i]<= '9' || s[i] >= 'a' && s[i] <= 'z' || s[i]=='-';i++) { c = s[i-1]; g = s[i]; n = s[i+1]; //printf("\nc = %cg = %cn = %c\n", c,g,n); if(s[0] == '-') printf("%c",s[0]); else if(g == '-') { if(c 

Разве это не проблема от K & R? Кажется, я видел его там. В любом случае, я надеюсь, что помог.

Исходя из того факта, что существующая функция обращается к последовательностям «az» и «0-9» просто отлично, отдельно, мы должны исследовать, что происходит, когда они встречаются. Отслеживайте свой код (попробуйте напечатать значение каждой переменной на каждом шаге – да, он будет загроможден, поэтому используйте разрывы строк), и я считаю, что вы найдете логическое короткое замыкание, когда итерация, например, из «текущего токена» равна y ‘, а следующий токен -‘ z ” to ‘current token is’ z ‘, а следующий токен равен’ 0 ‘”. Исследуйте условие if (), и вы обнаружите, что оно не охватывает все возможности, т. Е. Вы охватили себя, если вы находитесь в пределах <-> z, в пределах 0 <-> 9, или точно равны ‘-‘, но вы не считаете себя в конце одного (az или 0-9) со своим следующим персонажем в начале следующего.

Просто для удовольствия я решил продемонстрировать себе, что C ++ действительно так же подходит для такого рода вещей.

Сначала проверьте, пожалуйста

Во-первых, позвольте мне определить требования немного более строго: я предположил, что он должен обрабатывать эти случаи:

 int main() { const std::string in("This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6"); std::cout << "input : " << in << std::endl; std::cout << "output: " << expand(in) << std::endl; } 

input : Это некоторый тест ez в 5-7 шагах; это работает: abc . Это тоже работает: bkce . Аналогично 8-4-6
output: Это несколько тестов efghijklmnopqrstuvwxyz в 567 шагах; это работает: abc . Это тоже работает: bcdefghijk . Аналогично 45678

Реализация C ++ 0x

Вот реализация (на самом деле несколько вариантов) в 14 строках (23, включая пробелы, комментарии) кода C ++ 0x 1

 static std::string expand(const std::string& in) { static const regex re(R"([az](?:-[az])+|[0-9](?:-[0-9])+)"); std::string out; auto tail = in.begin(); for (auto match : make_iterator_range(sregex_iterator(in.begin(), in.end(), re), sregex_iterator())) { out.append(tail, match[0].first); // char range bounds: the cost of accepting unordered ranges... char a=127, b=0; for (auto x=match[0].first; x 

Конечно, я немного обманываю, потому что я использую iteratorы регулярных выражений от Boost. Я буду делать некоторые тайминги по сравнению с версией C для производительности. Я скорее ожидаю, что версия C ++ будет конкурировать в пределах 50%. Но давайте посмотрим, какие сюрпризы для нас компилятор GNU ах ...

Вот полная программа, которая демонстрирует ввод образца. _ Он также содержит некоторые контрольные тайминги и несколько вариантов, которые компромисс

  • функциональная гибкость
  • четкость / производительность

 #include  // only needed for the 'slow variant' #include  #include  using namespace boost; using namespace boost::range; static std::string expand(const std::string& in) { // static const regex re(R"([az]-[az]|[0-9]-[0-9])"); // "acd" --> "abc-d", "aceg" --> "abc-efg" static const regex re(R"([az](?:-[az])+|[0-9](?:-[0-9])+)"); std::string out; out.reserve(in.size() + 12); // heuristic auto tail = in.begin(); for (auto match : make_iterator_range(sregex_iterator(in.begin(), in.end(), re), sregex_iterator())) { out.append(tail, match[0].first); // char range bounds: the cost of accepting unordered ranges... #if !SIMPLE_BUT_SLOWER // debug 15.149s / release 8.258s (at 1024k iterations) char a=127, b=0; for (auto x=match[0].first; x bounds(match[0].first, match[0].second); bounds.erase('-'); for (char c=*bounds.begin(); c<=*bounds.rbegin(); out.push_back(c++)); #endif tail = match.suffix().first; } out.append(tail, in.end()); return out; } int main() { const std::string in("This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6"); std::cout << "input : " << in << std::endl; std::cout << "output: " << expand(in) << std::endl; } 

1 Скомпилирован с g++-4.6 -std=c++0x