ランダムな文字列を解析し、そこからすべての整数を抽出して配列に入れる (比較的) 簡単な方法を探しています。
例:
pt112parah salin10n m5:isstupid::42$%&%^*%7first3
最終的には、次の内容の配列を取得する必要があります。
112 10 5 42 7 3
そして、文字列を文字ごとに処理するよりも効率的なメソッドが必要です。
ご協力いただきありがとうございます
迅速な解決策。long
の範囲を超える数値はなく、心配するマイナス記号もないと仮定しています。それらが問題である場合は、結果を分析するためにさらに多くの作業を行う必要があり、その後に数字strtol()
を検出する必要があります。'-'
コードはすべての文字をループします。それを避けることはできないと思います。ただしstrtol()
、数字の各シーケンスを処理するために使用し (最初の数字が見つかったら)、中断したところから再開strtol()
します (またstrtol()
、変換を停止した場所を正確に教えてくれます)。
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
const char data[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
long results[100];
int nresult = 0;
const char *s = data;
char c;
while ((c = *s++) != '\0')
{
if (isdigit(c))
{
char *end;
results[nresult++] = strtol(s-1, &end, 10);
s = end;
}
}
for (int i = 0; i < nresult; i++)
printf("%d: %ld\n", i, results[i]);
return 0;
}
出力:
0: 112
1: 10
2: 5
3: 42
4: 7
5: 3
一日中 Python を書いていて、休憩が必要だからです。配列の宣言はトリッキーです。これを 2 回実行して数値を計算する (そして配列を割り当てる) か、この例のように数値を 1 つずつ使用する必要があります。
注意: '0' から '9' までの ASCII 文字は 48 から 57 (連続) です。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
int length = strlen(input);
int value = 0;
int i;
bool gotnumber = false;
for (i = 0; i < length; i++)
{
if (input[i] >= '0' && input[i] <= '9')
{
gotnumber = true;
value = value * 10; // shift up a column
value += input[i] - '0'; // casting the char to an int
}
else if (gotnumber) // we hit this the first time we encounter a non-number after we've had numbers
{
printf("Value: %d \n", value);
value = 0;
gotnumber = false;
}
}
return 0;
}
編集: 以前のバージョンは 0 を処理しませんでした
文字ごとに調べるよりも効率的ですか?
整数ではないことを知るためにすべての文字を調べる必要があるため、不可能です。
ここで、文字列を 1 文字ずつ調べなければならないことを考えると、単純に各文字を int としてキャストし、次のことを確認することをお勧めします。
//string tmp = ""; declared outside of loop.
//pseudocode for inner loop:
int intVal = (int)c;
if(intVal >=48 && intVal <= 57){ //0-9 are 48-57 when char casted to int.
tmp += c;
}
else if(tmp.length > 0){
array[?] = (int)tmp; // ? is where to add the int to the array.
tmp = "";
}
配列にはソリューションが含まれます。
また、Cの代わりにC ++を使用してもかまわない場合(通常、理由はありません)、ソリューションを2行のコードに減らすことができます(AXパーサージェネレーターを使用)。
vector<int> numbers;
auto number_rule = *(*(axe::r_any() - axe::r_num())
& *axe::r_num() >> axe::e_push_back(numbers));
今それをテストします:
std::string str = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
そして確かに、あなたはあなたの数を取り戻しました。
また、ボーナスとして、Unicode幅の文字列を解析するときに何も変更する必要はありません。
std::wstring str = L"pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
そして確かに、あなたは同じ数を取り戻しました。
別の解決策は、strtok
関数を使用することです
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," abcdefghijklmnopqrstuvwxyz:$%&^*");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " abcdefghijklmnopqrstuvwxyz:$%&^*");
}
return 0;
}
与えます:
112
10
5
42
7
3
トークンとして扱われるすべての文字を指定する必要があるため、おそらくこのタスクには最適なソリューションではありません。しかし、これは他のソリューションに代わるものです。
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(void)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
char *pos = input;
int integers[strlen(input) / 2]; // The maximum possible number of integers is half the length of the string, due to the smallest number of digits possible per integer being 1 and the smallest number of characters between two different integers also being 1
unsigned int numInts= 0;
while ((pos = strpbrk(pos, "0123456789")) != NULL) // strpbrk() prototype in string.h
{
sscanf(pos, "%u", &(integers[numInts]));
if (integers[numInts] == 0)
pos++;
else
pos += (int) log10(integers[numInts]) + 1; // requires math.h
numInts++;
}
for (int i = 0; i < numInts; i++)
printf("%d ", integers[i]);
return 0;
}
strpbrk()
整数の検索は、オフセット ポインターでを繰り返し呼び出すことによって行われます。ポインターは、整数の 10 を底とする対数を見つけて 1 を加算することによって計算される、整数の桁数に等しい量だけオフセットされます (特別な整数が 0 の場合)。abs()
整数は非負になると述べたので、対数を計算するときに整数を使用する必要はありません。スペース効率を高めたい場合は、整数はすべて<256になると述べたように、unsigned char integers[]
ではなくを使用できますint integers[]
が、それは必須ではありません。