C言語関係掲示板

過去ログ

No.398.可変個のパラメタを指定する方法

[戻る] [ホームページ]
No.2736

可変個のパラメタを指定する方法
投稿者---yukki(2002/09/19 11:18:50)


第一引数で指定された文字列の先頭または終端から、
第二引数で指定された文字列を削除する関数を作成しました。

第二パラメタで可変個の文字列を指定できるように改造したいのですが、
どのように改造したらよいか、思いつきません。
よい案がありましたら教えていただけないでしょうか?
よろしくお願い致します。

<改造前>
パラメタ例:
第一引数:"(abc"
第二引数:"("
実行後文字列:abc

<改造後>
パラメタ例:
第一引数:"( )abc.))"
第二引数:"(",")","."," ",","
実行後文字列:abc

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

long strdelEX
(
char *buf, /* 編集対象文字列 */
char *src /* 削除文字列 */
);

void main( void )
{
char buf[128];
int iRtn;

strcpy( buf, "(abc" );
printf( "編集前文字列=%s\n", buf );

iRtn = strdelEX( buf, "(" );
if( -1 == iRtn )
{
printf( "error" );
return;
}

printf( "編集前文字列=%s\n", buf );
return;
}

/* 第一引数で指定された文字列の先頭または終端から、 */
/* 第二引数で指定された文字列を削除する関数 */
long strdelEX
(
char *buf, /* 編集対象文字列 */
char *src /* 削除文字列 */
)
{
char *q; /* 検索文字列へのポインタ*/
long l;

if ( 0 == ( l = strlen( src ) ) )
{
return( -1 );
}

q = buf;
if( 0 == strncmp( q, src, strlen( src ) ) )
{
strcpy( buf, q + strlen( src ) );
}

if( 0 == strncmp( q + strlen( buf ) - strlen( src ), src, strlen( src ) ) )
{
buf[ strlen( buf ) - strlen( src ) ] = '\0';
}

return( strlen( buf));
}</pre>

No.2743

Re:可変個のパラメタを指定する方法
投稿者---かずま(2002/09/19 17:08:38)


> 第一引数で指定された文字列の先頭または終端から、
> 第二引数で指定された文字列を削除する関数を作成しました。
>
> 第二パラメタで可変個の文字列を指定できるように改造したいのですが、
> どのように改造したらよいか、思いつきません。

> <改造後>
> パラメタ例:
> 第一引数:"( )abc.))"
> 第二引数:"(",")","."," ",","
> 実行後文字列:abc

先頭でも、終端でもない ")" が削除されていますね。ということは、
改造で作るより新規で作ったほうがよいと思います。
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

void strdel(char *buf, const char *str)
{
    char *p = buf;  int len = strlen(str);

    while ((p = strstr(p, str)) != NULL)
        strcpy(p, p + len);
}

void strdelEX(char *buf, ...)
{
    char *p;  va_list ap;

    va_start(ap, buf);
    while ((p = va_arg(ap, char *)) != NULL && *p != '\0')
        strdel(buf, p);
    va_end(ap);
}

int main()
{
    char str[] = "( )abc.))";

    puts(str);
    strdelEX(str, "(", ")", ".", " ", ",", NULL);
    puts(str);
    return 0;
}


No.2745

私の説明が不明確でした
投稿者---yukki(2002/09/19 17:30:17)


ごめんなさい、私の書き方が不明確でした。
第二パラメタで指定された文字(文字列)が、
第一パラメタの両端にはこないようにしたいのです。

以下の例でいうと、
"a()bc"の中にある"()"は文字列の両端ではないので、
そのまま残したいんです。

パラメタ例:
第一引数:"( )a()bc.))"
第二引数:"(",")","."," ",","
実行後文字列:a()bc



No.2749

Re:私の説明が不明確でした
投稿者---かずま(2002/09/19 18:54:26)


> 第二パラメタで指定された文字(文字列)が、
> 第一パラメタの両端にはこないようにしたいのです。
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

void strdelEX(char *buf, ...)
{
    int buflen, pos;  char *p;  va_list ap;

    do {
        buflen = strlen(buf);
        va_start(ap, buf);
        while ((p = va_arg(ap, char *)) != NULL && *p != '\0') {
            pos = buflen - strlen(p);
            if (pos >= 0 && strcmp(buf + pos, p) == 0) {
                buf[pos] = '\0';
                break;
            }
        }
        va_end(ap);
    } while (p != NULL && *p != '\0');

    do {
        va_start(ap, buf);
        while ((p = va_arg(ap, char *)) != NULL && *p != '\0') {
            if (memcmp(buf, p, strlen(p)) == 0) {
                strcpy(buf, buf + strlen(p));
                break;
            }
        }
        va_end(ap);
    } while (p != NULL && *p != '\0');
}

int main()
{
    char buf[] = "( )a()bc.))";

    puts(buf);
    strdelEX(buf, "(", ")", ".", " ", ",", NULL);
    puts(buf);
    return 0;
}


No.2750

Re:私の説明が不明確でした
投稿者---かずま(2002/09/19 20:22:53)


改良版です。
void strdelEX(char *buf, ...)
{
    int n, buflen = strlen(buf);  char *p;  va_list ap;

    do {
        n = 0;
        va_start(ap, buf);
        while ((p = va_arg(ap, char *)) != NULL && *p) {
            int i, len = strlen(p);
            for (i = buflen - len; i >= 0 && !strcmp(buf + i, p); i -= len)
                buf[i] = '\0',  n += len;
            while (memcmp(buf, p, len) == 0)
                strcpy(buf, buf + len),  n += len;
        }
        va_end(ap);
        buflen -= n;
    } while (n != 0);
}


No.2757

Re:私の説明が不明確でした
投稿者---aki(2002/09/20 03:22:25)


>while (memcmp(buf, p, len) == 0)
>    strcpy(buf, buf + len),  n += len;

このstrcpyではコピー元の領域とコピー先の領域が重なる可能性
があり、その場合の動作は未定義となってます。おそらく問題ない
んでしょうけど。

No.2756

Re:私の説明が不明確でした
投稿者---aki(2002/09/20 03:10:16)


>第二引数:"(",")","."," ",","

上の例での5つの文字列は、いずれも1文字だけの文字列ですが、
2文字以上の文字列を指定することもありえるんでしょうか?

つまり、次のような使い方をすることもありえますか?

strcpy(buf, "abxb--axxb");
strdelEX(buf, "ab", "xxb");

もしそうだとすると、この例での結果の文字列は、"xb--a"で
いいんでしょうか?

もし、1文字の文字列しか指定しないのなら、次のように削除し
たい文字(列)を一つの文字列にまとめてしまえば簡単です。
#include <stdio.h>
#include <string.h>

/* str が指す文字列の両端から rchars が指す文字列中の文字を削除する */
char *strdelEX(char *str, const char *rchars)
{
    char    *left, *right;

    left = str + strspn(str, rchars);
    right = strchr(str, '\0');
    while (left < right && strchr(rchars, right[-1]))
        right--;

    memmove(str, left, right - left);
    str[right - left] = '\0';
    return str;
}

int main(void)
{
    char str[] = "( )a()bc.))";

    printf("%s\n", str);
    strdelEX(str, "(). ,");
    printf("%s\n", str);

    return 0;
}


No.2748

自己レスです
投稿者---yukki(2002/09/19 18:25:53)


strdelEX()の仕様はそのままに、
呼び出し方を変えてみました。
これなら"( )a()bc.))"→"a()bc"という文字列操作が可能かな、と。

void main( void )
{
        char    buf[128];
        int             iRtn;
        int             strLen;

        strcpy( buf, "( )a()bc.))" );
        printf( "編集前文字列=%s\n", buf );

        strLen = strlen( buf );
        iRtn = strLen - 1;

        while( iRtn < strLen )
        {
                strLen = strlen( buf );
                iRtn = strdelEX( buf, "(" );
                iRtn = strdelEX( buf, ")" );
                iRtn = strdelEX( buf, "." );
                iRtn = strdelEX( buf, "," );
                iRtn = strdelEX( buf, " " );
        }

        printf( "編集前文字列=%s\n", buf );
        return;
}


No.2766

ありがとうございます
投稿者---yukki(2002/09/23 21:14:54)


かずまさん、akiさん、どうもありがとうございました。

かずまさんに教えていただいた方法を使ってみましたが、
akiさんのような方法もあるのですね。

やはりC言語の文字列操作は難しいです。。

ありがとうございました。