文字列内から整数を抽出するにはどうすればよいですか?


8

私は割り当てに取り組んでおり、その一部として文字列から整数を抽出する必要があります。

atoi()関数を使用しようとしましたが、常にを返します0。そのため、に切り替えましたstrtol()が、それでもを返します0

目標は、文字列から整数を抽出し、それらを引数として別の関数に渡すことです。これらの値を使用して一部のデータを更新する関数を使用しています(update_stats)。

私はC言語でプログラミングするのはかなり初めてですが、これは私の試みでした。

void get_number (char str[]) {
    char *end;
    int num;
    num = strtol(str, &end, 10);
    update_stats(num);
    num = strtol(end, &end, 10);
    update_stats(num);
}

これの目的は文字列内にあります"e5 d8"(たとえば)私はその文字列から5とを抽出8します。

文字列の形式は常に同じです。

これどうやってするの?


1
コードのこの部分には明らかなバグがないため、問題を再現できません。
ランディン

1
ループを使用して、使用するisdigit前に数字以外のすべての文字をスキップすることができますstrtol
Bodo

1
との両方が、数字の最初の文字へのポインタを受け取ることatoistrtol期待しています。ポインタはすでに数字を指している必要があります。基数が10の場合、「e」も「d」も数字ではありません。文字列内の数字を見つけるには、各文字を調べて数字かどうかを判断するコードを記述する必要があります。数字を見つけたら、必要に応じて、その数字(1桁のみ)または一連の数字(数桁)を数値に変換できます。
Eric Postpischil

@Lundin:完全に明らかなバグがあります。最初の文字へのポインタを渡す"e5 d8"には、strtol「5」を見つけると数に変換するための正しい方法ではありません。
Eric Postpischil

@EricPostpischil確かに、それが実際の入力である場合。呼び出しコードなしではわかりにくい。
ランディン

回答:


7

strtol文字列から数値が見つかりません。文字列の先頭の数値変換します。(空白はスキップしますが、それ以外は何もしません。)

番号が始まる場所を見つける必要がある場合は、次のようなものを使用できます。

const char* nump = strpbrk(str, "0123456789");
if (nump == NULL) /* No number, handle error*/

man strpbrk

番号が署名される可能性がある場合は、もう少し洗練されたものが必要になります。1つの方法は、上記を実行し、前の文字がの場合は1文字をバックアップすることです-。ただし、文字列の先頭に注意してください。

if ( nump != str && nump[-1] == '-') --nump;

ただ、パッティング-strpbrkのような入力に誤った一致を生成する引数non-numeric7


2

フォーマットが常にこのようなものであれば、これも機能する可能性があります

#include <stdio.h>

int main()
{
    char *str[] = {"a5 d8", "fe55 eec2", "a5 abc111"};
    int num1, num2;

    for (int i = 0; i < 3; i++) {
      sscanf(str[i], "%*[^0-9]%d%*[^0-9]%d", &num1, &num2);
      printf("num1: %d, num2: %d\n", num1, num2);
    }
    return 0;
}

出力

num1: 5, num2: 8                                                                                                                                                                   
num1: 55, num2: 2                                                                                                                                                                  
num1: 5, num2: 111

%[^0-9]数字以外の文字と一致します。を追加することで、*これ%*[^0-9]はデータが文字列から読み取られるが無視されることを示します。


の素敵な使い方sscanf。本当に感謝しています。ただし、その形式が当然のことと考えられている方法であることはどこにも明記されていません。可能であれば、もう少し一般性を追加してみてください。また、ユーザーがI / Oと文字列から整数への変換で立ち往生している場合は、新しい可能性が高いです。したがって、ドキュメンテーションへのリンクを追加するか、少なくとも提供することは非常に役立ちます。たとえば、この場合は、sscanfです。でもいい答えです:)
d4rk4ng31

1
よろしくお願いします。ただし、質問には「文字列の形式は常に同じです。」とあります。これは、これが同じである可能性があることを意味します。ジェネリシティは良いことですが、それがないとソリューションはこのように機能します。googleの最初のヒットsscanfはドキュメントです。ここで本当に改善されるのは、ここで追加する可能性のある形式の小さな説明だと思います。
エラクロン

そうだね。ごめんなさい。私は最後の声明を逃したと思います。でもいい答えです:)
d4rk4ng31

2

ロジックは自分で書くことをお勧めします。ホイールを再発明するようなものですが、その場合は、ライブラリ関数が実際にどのように機能するかを理解できます。

ここに私が提案する関数があります:

bool getNumber(str,num_ptr)
char* str;
long* num_ptr;
{
    bool flag = false;
    int i = 0;
    *num_ptr = 0;
    char ch = ' ';
    while (ch != '\0') {
        ch = *(str + i);
        if (ch >= '0' && ch <= '9') {
            *num_ptr = (*num_ptr) * 10 + (long)(ch - 48);
             flag = true;
        }
        i++;
    }
    return flag;
}

\0最後にaが付いた文字列を渡すことを忘れないでください:)


この関数は文字列全体をスキャンし、順番に数字で構成される数値を返します。
d4rk4ng31

考えるとc、あなたはintにブール値に変換してもtruefalse1して0、それぞれ
d4rk4ng31
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.