C言語関係掲示板

過去ログ

No.1256 文字列中から文字列を取り出し

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

文字列中から文字列を取り出し
投稿者---剛(2004/09/03 22:47:02)


文字列中から数字のみを取り出しているのですが、
取り出した文字列中が、指定の長さ以上にの時は、
数字以外の文字列が最初に現れる直前の部分を取り
除いて、再度。指定の長さのチェックをして取得
したいのですが、

同じ処理を再度、書くのも芸がないと思うのですが
何か、スマートなロジックはないですか。

#include <stdio.h>

#define iskanji(c) ((c & 0xFF) >= 0x81 && (c & 0xFF) <= 0x9F || (c & 0xFF) >= 0xE0 && (c & 0xFF) <= 0xFC)
#define MOJI_LEN 8

int edit_string(char *) ;

main()
{
    //char str[] = "12345+67890+12345+67890" ;
    char str[] = "01+2345+6789" ;

    if (edit_string(str) != 0) {
        exit(-1) ;
    }
    printf("[%s]\n",str) ;

    exit(0) ;
}

int edit_string(char *str)
{
    char *p ;
    char wk_str[65] ;
    char c ;
    int i ;
    int j=0 ;

    memset(wk_str,'\0',sizeof(wk_str)) ;
    p = str ;

    for (i=0; *p;) {
        c = *p ;
        if (iskanji(c)) {
            return(-1) ;
        }

        if (*p >= 0x30 && *p <= 0x39) {
            wk_str[i++] = *p ;
            p++ ;
        } else {
            p++ ;
        }
    }

    if (strlen(wk_str) > MOJI_LEN) {
        p = str ;
        memset(wk_str,'\0',sizeof(wk_str)) ;

        while (*p) {
            if (*p < 0x30 || *p > 0x39) {
                p++ ;
                break ;
            }
            p++ ;
        }
        for (i=0; *p;) {
            if (*p >= 0x30 && *p <= 0x39) {
                wk_str[i++] = *p ;
                p++ ;
            } else {
                p++ ;
            }
            if (i > MOJI_LEN) {
                return(-1) ;
            }
        }
    }

    strncpy(str,wk_str,strlen(wk_str)) ;
    *(str+strlen(wk_str)) = '\0' ;

    return(0) ;
}




No.16569

Re:文字列中から文字列を取り出し
投稿者---Sciggepy(2004/09/03 23:00:34)


>文字列中から数字のみを取り出しているのですが、
>取り出した文字列中が、指定の長さ以上にの時は、
>数字以外の文字列が最初に現れる直前の部分を取り
>除いて、再度。指定の長さのチェックをして取得
>したいのですが、
>
>同じ処理を再度、書くのも芸がないと思うのですが
>何か、スマートなロジックはないですか。
非常に読みにくいです。私の毒か威力では、何を求められているのかが分かりません。

あと、
    for (i=0; *p;) {
        c = *p ;
        if (iskanji(c)) {
            return(-1) ;
        }

        if (*p >= 0x30 && *p <= 0x39) {
            wk_str[i++] = *p ;
            p++ ;
        } else {
            p++ ;
        }
    }
は冗長に見えます。
    for (i=0; *p; p++) {
        if (iskanji(*p)) return(-1) ;
        if (*p >= 0x30 && *p <= 0x39)
            wk_str[i++] = *p ;
    }



No.16571

"剛さんの投稿" から "ロジック" を取り出し
投稿者---shu(2004/09/04 00:20:50)


>何か、スマートなロジックはないですか。

この場合、アルゴリズムという言葉の方が適切と思います。

過去ログより
goo 辞書調べ


No.16572

Re:文字列中から文字列を取り出し
投稿者---あかま(2004/09/04 00:43:31)


ちょっとやりたいことがわかりにくい。
こういうときは、入力例と出力例を書くと分かりやすいと思いますよ。


No.16574

Re:文字列中から文字列を取り出し
投稿者---剛(2004/09/04 01:31:42)


やりたいことは以下の通りです。

01+2345+5678

数字だけを取り出す。

0123456789

この時、取り出した文字列が指定の長さより長い場合、
再度、文字列の取り出しを行う。

数字以外の文字列が最初に現れる直前の部分を取り除く
 ↓
2345678

としたい



No.16576

Re:文字列中から文字列を取り出し
投稿者---ぽこ(2004/09/04 03:03:30)


これって文字列の後ろから欲しいだけ数字を取り出すだけで済みませんか?


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

static int edit_string(char * s1, const char * s2, unsigned int size) ;
static int reverse(char * str, unsigned int n);

int 
main(void)
{
    //char str[] = "12345+67890+12345+67890" ;
    char str[] = "01+2345+6789" ;
    char buf[9];

    if (edit_string(buf,str,8) != 0) {
        return -1;
    }

    printf("[%s]\n",buf) ;
    return 0;
}

static int 
edit_string(char *s1, const char * s2, unsigned int size)
{
    char * p1 = s1;
    const char * p2 = s2 + strlen(s2);
    unsigned int i;

    // 文字列の後ろからsize文字取得
    for(i = 0; (p2 != s2) && (i < size); --p2) {
        if ('0' <= *p2 && *p2 <= '9') {
            *p1++ = *p2;
            ++i;
        }
    }

    // 配列を反転
    reverse(s1, i);

    // 終端文字の挿入
    *p1 = '\0';

    return 0 ;
}

static int 
reverse(char * str, unsigned int n)
{
    unsigned int i = 0;
    char ch;

    for(; i<n-1; ++i,--n) {
        ch = str[i];
        str[i] = str[n-1];
        str[n-1] = ch;
    }

    return 0;
}



No.16577

Re:文字列中から文字列を取り出し
投稿者---Sciggepy(2004/09/04 11:32:39)


多分、違うと思います。

MOJI_LENが8のとき、

01+23456+789+01234+56



23456+789+01234+56
789+01234+56
0123456(結果)

として取り出すのだと思います。
最初のは2回しか判定していないようでしたが、
#include <stdio.h>

#define MOJI_LEN 8

int edit_str(const char *s,char *rs)
{
    int i,c,n;
    for(i=0,c=0,n=0;s[i];i++)
        if(s[i]>='0'&&s[i]<='9') {
            if(c<=MOJI_LEN) rs[c++]=s[i];
        } else if(!n) n=i+1;
    if(c>MOJI_LEN) {
        if(n) return edit_str(s+n,rs);
        else return -1;
    }
    rs[c]='\0';
    return 0;
}

int main(void)
{
    char s[]="01+23456+789+0123455644",rs[MOJI_LEN+1];
    if(edit_str(s,rs)!=0) return -1;
    printf("%s",rs);
    return 0;
}
ですか?


No.16578

Re:文字列中から文字列を取り出し
投稿者---ぽこ(2004/09/04 12:49:50)


>多分、違うと思います。
>
>MOJI_LENが8のとき、
>
>01+23456+789+01234+56
>
>を
>
>23456+789+01234+56
>789+01234+56
>0123456(結果)
>
>として取り出すのだと思います。

すみません。
この例だと私が提示したロジックと同じ結果にしかなりませんが、
"後ろから欲しいだけ数字取得する"では駄目な例を挙げていただけないでしょうか?

#MOJI_LENが8なのに最大7文字というのは奇妙ですよね。。。
#剛さんが提示した例ではそうなってますが、
#説明では"取り出した文字列が指定の長さより長い場合"となっている。



   
No.16584

Re:文字列中から文字列を取り出し
投稿者---Sciggepy(2004/09/04 14:27:37)


>すみません。
>この例だと私が提示したロジックと同じ結果にしかなりませんが、
>"後ろから欲しいだけ数字取得する"では駄目な例を挙げていただけないでしょうか?
本当のところはよく分からないのですが、指定文字数(ここでは8文字)の数字を最後から取り出すのでは、

01+23456+789+01234+56
90123456

となります。私が想定した処理は、

01+23456+789+01234+56
01234567890123456(8文字より長い)
23456+789+01234+56(01+を除く)
234567890123456(8文字より長い)
789+01234+56(23456+を除く)
7890123456(8文字より長い)
01234+56(789+を除く)
0123456(8文字以内)
0123456(結果)

です。



No.16579

Re:文字列中から文字列を取り出し
投稿者---ごんべ(2004/09/04 13:18:50)


>MOJI_LENが8のとき、
>
>01+23456+789+01234+56
>
>を
>
>23456+789+01234+56
>789+01234+56
>0123456(結果)
>
>として取り出すのだと思います。

あっていると思いますが
詳しい仕様はわかりませんが、数字のみの文字列にして、その長さが
MOJI_LENより長い場合は、前の方の部分(数字以外の文字の部分)までを
削って、最終的には、MOJI_LENの長さ以内にしたいんじゃないでしょうか。
また、最後に求められた値の長さが、MOJI_LENより長い場合は、いらない
(エラー)とするかな。?

じゃないんでしょうか。


No.16580

Re:文字列中から文字列を取り出し
投稿者---剛(2004/09/04 13:32:22)


ぽこさん、Sciggepyさん、他の皆様ありがとうございます。

曖昧な説明ですみません。
#define MOJI_LEN 8

01+2345+5678

数字だけを取り出す。

0123456789

この時、取り出した文字列がMOJI_LEN より長い場合、
再度、文字列の取り出しを行う。
最初の数字以外の文字の場所までをを取り除く。
「01+」を取り除く
 ↓
2345678

としたい
MOJI_LENの長さ以内にしたいのです。

後ろから参照するするにも一つ問題があり、
文字列が一つではないのです。

char str[]="01+23456+789+01234+56,01+23456+789+01234+56,01+23456+789+01234+56"

になっており、最初に現れる文字列だけを使いたいのです。
また、例では、カンマで区切られていますが、コロンであったり
半角スペース等であったりしています。



No.16582

Re:文字列中から文字列を取り出し
投稿者---あかま(2004/09/04 14:11:18)


>曖昧な説明ですみません。
まだいろいろ曖昧。

>#define MOJI_LEN 8
>
>01+2345+5678
>↓
>数字だけを取り出す。
>↓
>0123456789
ここで'5'がひとつ消えてるのですが。

>この時、取り出した文字列がMOJI_LEN より長い場合、
>再度、文字列の取り出しを行う。
>最初の数字以外の文字の場所までをを取り除く。
>「01+」を取り除く
> ↓
>2345678
>
>としたい
>MOJI_LENの長さ以内にしたいのです。
最大長が8のとき、12345+5678は
+で区切られているブロックを切り出しの区切りにして

5678

になるのですか?
それとも最大長にあわせて

12345678

になるのですか?流れを読む限りこれでもめてる気がします。

>後ろから参照するするにも一つ問題があり、
>文字列が一つではないのです。
>
>char str[]="01+23456+789+01234+56,01+23456+789+01234+56,01+23456+789+01234+56"
>
>になっており、最初に現れる文字列だけを使いたいのです。
C言語では'\0'で終わるまでが1つの文字列として扱われます。
>文字列が一つではないのです。
という書き方をすると混乱の元です。
「文字列の中に区切り文字があって、最初の区切り文字までを処理したい」
でよいですか?

>また、例では、カンマで区切られていますが、コロンであったり
>半角スペース等であったりしています。
カンマ、コロン、半角スペースが文字列を区切るのはわかったのですが、
'等'がつくと他に何を区切り文字としていいのかわかりません(区切り文字すべてを処理として書かなければいけないから)。
「'+'と数字以外はすべて区切り文字」
でいいですか?




No.16583

Re:文字列中から文字列を取り出し
投稿者---ぽこ(2004/09/04 14:11:54)


提示されている例と説明が一致せずに混乱しています。。

1.タイプミス?
>数字だけを取り出す。
>↓
>0123456789
'5'が消えて'9'が現れていますが。。

2.「長い」「以内」
>この時、取り出した文字列がMOJI_LEN より長い場合、
>再度、文字列の取り出しを行う。
>最初の数字以外の文字の場所までをを取り除く。
>「01+」を取り除く
> ↓
>2345678
>
>としたい
>MOJI_LENの長さ以内にしたいのです。

数字列が9文字以上(MOJI_LENより長い)のとき
8文字以下(MOJI_LENの長さ以内)にしたいと言ってますが、
結果は7文字になっていますね。何故8文字じゃないのですか?
何故7文字になったのか、そのルールを明記してください。

#6文字や5文字とかは現れたりするのですか?

3.区切り文字
>後ろから参照するするにも一つ問題があり、
>文字列が一つではないのです。
#衝撃の新事実^^;

>また、例では、カンマで区切られていますが、コロンであったり
>半角スペース等であったりしています。

仕様を説明する上で、"等"と言う言葉は絶対に使わないで下さい。
カンマ、コロン、半角スペース以外の区切り文字には何があるのですか?
「全て」列挙してください。

#他に「実は○○なんです。」ってことはありますか?



No.16585

【再説明】文字列中から文字列を取り出し
投稿者---剛(2004/09/04 15:23:47)


あかまさん、ぽこさん、Sciggepyさん、他の皆様ありがとうございます。

説明でタイプミスがありました。
再度、説明させていただきます。

01+2345+6789(数字だけを取り出す)
0123456789(8文字より長い)
2345+6789(01+を除く)
23456789(8文字以内)

結果:2345678

01-2345-6789-12345-67890
01234567891234567890(8文字より長い)
2345-6789-12345-67890(01-を除く)
234567891234567890(8文字より長い)
6789-12345-67890(2345-を除く)
67891234567890(8文字より長い)
12345-67890(6789-を除く)
1234567890(8文字より長い)
67890(12345-を除く)
67890(8文字以内)

結果:67890

01+23456789+1234567890
0123456789123456789(8文字より長い)
23456789-1234567890(01+を除く)
23456789123456789(8文字より長い)
1234567890(23456789+を除く)
1234567890(8文字より長い)

結果:エラーとする。(エラーリターン)

としたいのです。

>>char str[]="01+23456+789+01234+56,01+23456+789+01234+56,01+23456+789+01234+56"
>>になっており、最初に現れる文字列だけを使いたいのです。
>C言語では'\0'で終わるまでが1つの文字列として扱われます。

>>文字列が一つではないのです。
>という書き方をすると混乱の元です。
>「文字列の中に区切り文字があって、最初の区切り文字までを処理したい」
>でよいですか?
はい。
文字列の中に区切り文字があって、最初の区切り文字までを処理したいです。

>'等'がつくと他に何を区切り文字としていいのかわかりません(
>区切り文字すべてを処理として書かなければいけないから)。
>「'+'と数字以外はすべて区切り文字」
>でいいですか?
区切り文字は、カンマ「,」、コロン「:」、セミコロン「;」、半角スペース、
かダブルクォートで囲まれています。

>#6文字や5文字とかは現れたりするのですか?
現れます。
11
7777
という場合もあります。

他に、全角文字も含まれる場合もありますが、全角文字が現れた時点で、エラー
とします。
以前、私が書いたソースの中でやっているので、その処理を最初に行おうと思って
ます。



No.16586

Re:【再説明】文字列中から文字列を取り出し
投稿者---Sciggepy(2004/09/04 16:39:13)


どうやら、この解釈でよさそうですね。
http://www2.realint.com/cgi-bin/tarticles.cgi?pointc+16584

>文字列の中に区切り文字があって、最初の区切り文字までを処理したいです。
>
区切り文字を発見したら、ループを脱出するようにすればよいでしょう。



No.16587

Re:【再説明】文字列中から文字列を取り出し
投稿者---ぽこ(2004/09/04 17:20:30)


>どうやら、この解釈でよさそうですね。

そのようですね。

>区切り文字を発見したら、ループを脱出するようにすればよいでしょう。

データ群から1データ取る関数を別に作成した方がいいと思います。




No.16589

Re:【再説明】文字列中から文字列を取り出し
投稿者---剛(2004/09/04 18:05:02)


ぽこさん、Sciggepyさん、他の皆様ありがとうございます。

>>区切り文字を発見したら、ループを脱出するようにすればよいでしょう。
>
ループ内で、0〜9の数字チェックをしていますから、その後で、区切り文字
か読み飛ばしの文字かを判断する処理を組み込めばよいというこですか。

>データ群から1データ取る関数を別に作成した方がいいと思います。
>
文字を検索する関数があるので、区切り文字を検索して最初を取得。
でも、全角文字とかもチェックいるので、データ群から1データを
とってやるのがいいかのしれないです。




No.16605

Re:【再説明】文字列中から文字列を取り出し
投稿者---ごんべ(2004/09/05 22:14:30)


>>区切り文字は、カンマ「,」、コロン「:」、セミコロン「;」、半角スペース、
>かダブルクォートで囲まれています。

ダブルクォートで囲まれた場合もあるとことでしたら、データ群から1データ
を取る方が楽でしょ。

というようりは、取得方法については、すでにソースがありますから、必要な
データを取り出す方法が良いのでは。


No.16573

Re:文字列中から文字列を取り出し
投稿者---ぽこ(2004/09/04 01:31:11)


仕様が良く分かりませんが、こんな感じでしょうか。。

#include <stdio.h>

static int edit_string(char * s1, const char * s2, unsigned int size) ;

int 
main(void)
{
    //char str[] = "12345+67890+12345+67890" ;
    char str[] = "01+2345+6789" ;
    char buf[9];

    if (edit_string(buf,str,8) != 0) {
        return -1;
    }
    printf("[%s]\n",buf) ;
    return 0;
}

static int 
edit_string(char *s1, const char * s2, unsigned int size)
{
    char * p1 = s1;
    const char * p2 = s2;
    unsigned int i;

    do {
        for(p1 = s1,i = 0; *p2 && (i < size); ++p2) {
            if ('0' <= *p2 && *p2 <= '9') {
                *p1++ = *p2;
                ++i;
            }
        }
    }while(*p2);

    *p1 = '\0';
    return 0 ;
}




No.16575

Re:文字列中から文字列を取り出し
投稿者---ぽこ(2004/09/04 01:37:30)


>仕様が良く分かりませんが、こんな感じでしょうか。。
サイズが足りないときの処理が違いますね。。


No.16581

Re:文字列中から文字列を取り出し
投稿者---剛(2004/09/04 13:43:06)


char str[] = "01+2345+6789" ;

23456789
を期待いていたのですが
89
となります。