LINUX.ORG.RU

printf с заранее не известным количеством аргументов

 ,


0

2

На входе строка с некоторым количеством «%s». Все «%s» нужно заменить на одну и ту же строку.

Вопрос — есть ли способ использовать для этих целей printf?
Может можно как-то без ассемблера запихать в стек столько указателей на строку сколько хочется?
Или лучше самому всё сделать, без printf?

Проверку на другие возможные флаги после '%', сделаю вместе с подсчётом «%s».

ну можно по одному сначала спринтфом заменять, а потом принтом печатать. Наверное

Bad_ptr ★★★★★
()

printf(и вообще форматирование строк) не предназначена для такого. лучше использовать цикл + форматирование, но фиксированным кол-вом масок.

AGUtilities ★★★
()
Ответ на: комментарий от Eddy_Em

+1

манипуляции с va_arg к сожалению не взлетят: http://stackoverflow.com/questions/3968585/expanding-va-list-portably.

т.ч. я тоже голосую за strstr, что-то вроде:

#include <stdio.h>
#include <string.h>

void
replace(char *hay, char *needle)
{
        char *p, *q;

        p = hay = strdup(hay);

        while ((q = strstr(p, "%s"))) {
                *q = '\0';
                if (p)
                        fputs(p, stdout);
                fputs(needle, stdout);
                p = q + 2;
        }

        if (p)
                fputs(p, stdout);

        free(hay);
}

int
main()
{
        replace("%s aaa %s bbb %s ccc %s\n", "ddd");
        return 0;
}
beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: +1 от beastie

Обычно это нужно в переменную ввести, так что надо будет организовать динамически формируемую строку. Проще всего сделать так: найти все положения %s, подсчитав их количество (N); затем выделить требуемое количество памяти (strlen(hay) + N*(strlen(needle) - 2)) и начать заполнение.

Eddy_Em ☆☆☆☆☆
()
Ответ на: +1 от beastie

Не знаю насколько сложное форматирование будет в строке, но при использовании strstr(), «%%s» будет обработан неправильно, а цикл по символам сможет обработать и «%%s».

xaizek ★★★★★
()
Ответ на: комментарий от Eddy_Em

C printf это я погорячился. Выводить результат не всегда надо. Сделал так:

#include <stdlib.h>
#include <stdio.h>
#define _GNU_SOURCE
#include <string.h>

/* free it after usage */
char *replace(const char *str, const char *what, const char *with)
{
	char *result;
	const char *find = strstr(str, what);
	if (find == NULL)
	{
		result = strdup(str);
	}
	else
	{
		size_t
			count = 0,
			what_size = strlen(what);
		do
		{
			count++;
			find = strstr(&find[what_size], what);
		}
		while (find != NULL);

		size_t
			with_size = strlen(with),
			result_size = strlen(str) - what_size*count + with_size*count;
		result = malloc(result_size + 1);
		result[result_size] = '\0';

		find = strstr(str, what);
		const char *b4_find = str;
		void *next_to_last = result;
		do
		{
			next_to_last = mempcpy
			(
				mempcpy(next_to_last, b4_find, find - b4_find),
				with,
				with_size
			);
			b4_find = &find[what_size];
			find = strstr(b4_find, what);
		}
		while (find != NULL);
		strcpy(next_to_last, b4_find);
	}

	return result;
}

int main(int argc, char *argv[])
{
	puts(replace("%s you %sing %s", "%s", "fuck"));

	return EXIT_SUCCESS;
}

Как думаете, не слишком сложно?

Кстати, не смотря на «#define _GNU_SOURCE» warning всё равно выдаётся:

main.c:39: warning: implicit declaration of function ‘mempcpy’

LinuxUser ★★★
() автор топика
Ответ на: комментарий от LinuxUser

result = malloc(result_size + 1);

лучше заменить на calloc. Тогда даже если чуть символов «не хватит», в конце строки не будет мусора.

не слишком сложно?

Нормально, на мой взгляд.

не смотря на «#define _GNU_SOURCE» warning всё равно выдаётся

Можно попробовать #define __USE_GNU

Там, кстати, с этими define'ами иногда довольно забавные вещи происходят. Иной раз приходится чуть ли не с десяток #define'ов сделать, чтобы все нормально работало.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от imb

И правда. Вот же дурацкие эти инклюды: никогда не догадаешься, в каком порядке их надо разместить и куда дефайны поместить.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от xaizek

Ну, батенька, звиняйте: у ТС такого в ТЗ не было. А если рассматривать и такой случай, то придется для начала отловить все %%.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Sorcerer

эх, всю перепись быдлокодеров сорвали

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.