• ベストアンサー

入力された文字列から整数だけを取り出す方法

入力された文字列から整数だけを取り出すにはどうしたらよいのでしょうか? 例えば、 (1,1,4,4,2,3,2,3) と入力された時、'(' や ',' は無視して、 1 1 4 4 2 3 2 3 のみを取り出したいのですが。。 自分なりにiostreamの関数について調べてみたのですが、良い方法が思いつきません。 どなたかお力添えをお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • mha01
  • ベストアンサー率81% (9/11)
回答No.7

LippmanのC++プライマー(第4版)のp.340~p.342に、 8.5 stringストリーム という節があって、p.342に、 「istringstream を使って format_message(数値と文字列の並びが格納された ostringstream オブジェクト)を読めば数値を取り出すことができる。 文字列表現を数値に自動変換してくれるのである。 istringstream input_istring(format_message.str()); string dump; input_istring >> dump >> val1 >> dump >> val2;   」 て書いてありました。 input_istring の内容構成について知っていなければならない条件付きですけど。 ちなみにヘッダは sstream です。

voltaire00
質問者

お礼

これは便利ですね。 処理が短くなりそうで助かります。ありがとうございました。

その他の回答 (6)

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.6

>#5さん >※ "整数だけを取り出す"問題 1桁限定ならば、OKですね。 2桁以上の数値を取り出すことがあるならば、別の手立てが必要になりそうです。 まあ、そういう仕様があるかどうかは質問者さんしだいですけれど…。

回答No.5

C言語で単純に書いてみました。 #include <stdio.h> #include <stdlib.h> int main( void ) { char str[] = "(1,1,4,4,2,3,2,3)"; char *test; for (test=str; '\0' != (*test); test ++ ) { if ( ( *test >= '0' ) && ( *test <= '9' ) ) { printf("%c", *test ); } else { printf("%c", ' ' ); } } printf( "\n" ); } 数値のみを取り出したいという事で、目的をそのまま書きました。 入力値が"(1,1,4,4,2,3,2,3)"ではなく"#(1,1,4,4,2,3,2,3)"や"[1,1,4,4,2,3,2,3]","($1,&1#4!4,%2,=3,A2,BC3)"でも動作します。 ※ "整数だけを取り出す"問題でtokenが"(,"と固定されている問題ではなかったと感じましたので。 数字の確認部分、isdigit() 使っても良いし、符号("+-")や小数点(".")等も数値同様出力する様する事も可能です。

  • massano1
  • ベストアンサー率40% (4/10)
回答No.4

strtok()関数は文字列を破壊してしまうので複製を作りますが… 「複製を作らなければならない」のなら、デリミタを統一した複製を 初めに作ってしまおうというコードです。 --- #include <stdio.h> #include <stdlib.h> #include <string.h> #define NUMERIC "-0123456789" #define DELIMIT "," int main( void ) { char *string = "(1,1,(4,4),2,3,2,3),[-5,10],{20,-40}"; char *token, *delimit = DELIMIT; char *str; int i; if (str=(char *)malloc(strlen(string)+1)) { strcpy(str,string); for (i=0;*(str+i)!=0;i++) if (!strchr(NUMERIC,*(str+i))) *(str+i)=*delimit; token = strtok(str, delimit); while (token) { printf("%d\n", atoi(token)); token = strtok(NULL, delimit); } free(str); } return 0; } --- 但し、このコードは「123-123」という「-」で繋がっている場合の考慮を していません。よって「この形が出現しない」という前提でしか使えません。 この点を踏まえた上で参考にして下さい。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

こんな感じでどうですか? char *s = "(1,1,4,4,2,3,2,3)"; while (*s != '\0') {  char *ss = strpbrk(s, "+-0123456789");  if (ss == NULL) break;  s = ss;  errno = 0;  long value = strtol(s, &s, 10);  if (errno != 0) perror("error");  else printf("%ld\n", value); }

  • BLK314
  • ベストアンサー率55% (84/152)
回答No.2

C++言語で実装してみました。 ・()が複数あっても正しく動作する  ex (0,1), (1,2) オーバーフロー対策  (符号付き)整数に収まらない場合は処理しない 上に述べた事は”仕様"の問題で色々あると思います。 絶対に()は一組しか存在しないとか オーバーフロー時はエラーを表示するとか 今回の場合 strtoken()でももちろん実装できますし、 その方がスマートでもあるのですが、 ちょっとした弱点も抱え込むと考えます。 それは、"融通がきかない"ということです。 ()の他に{}でくくられている場合もある さらに、[]もあることがわかった .... その度にプログラムに修正を入れなければなりません。 デリミタ(区切り文字)をプログラムに埋め込む(ハードコーディング) でなく、設定ファイル等から読み込ませることにすれば かなり融通が利くようになりますが、 高々整数を取り出すのに、 その他の文字として何が使われいるか 調査しなければいけないのもつらいです。 整数なのだから 数字, 符号からなり それ以外は区切り文字にしてしまう方が扱い易いと思います。 それでは、ソースを載せます ====== ここから ソース ========================================== // StringTest.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #include <string> // 文字列処理にC++標準のStringクラスを用います #include <list> // 結果データ格納用 #include <errno.h> #include <iostream> using namespace std; // 文字が"整数"構成文字かチェックします static bool IsIntegerChar(char c) { if (isdigit(c)) return true; else if (c == '+' || c == '-') return true; else return false; } int main(int argc, char* argv[]) { // 元々の文字列です const char src[] = "(0, 1),(+2147483647, -2147483648, 2147483648, -2147483646)"; string s; // "整数"の候補格納用 list<int> tbl; // 結果の // 文字列を先頭から最後までサーチします for (const char* p = src; *p != '\0'; p++) { // 取り扱うのが整数のみなので // 文字としては数字及び+,-の符号のみが許されます。 char c = *p; if (IsIntegerChar(c)) { // 整数の候補を検出しました // まだ候補でしかないので保存しておきます s += c; } else { // 整数を表しえない文字です // 整数候補文字列の開始前か終了後です if (!s.empty()) { // 整数候補文字列の終わりです // 整数かどうかチェックを行います int n = atoi(s.c_str()); if (errno != ERANGE) { // 整数として変換できました // 後でまとめて表示するため // リストに格納します tbl.push_back(n); } // 新たな整数候補を探すため // 格納域をクリアします s.clear(); } } } // 文字列全体のサーチが終了しました // 整数を表示します for(list<int>::iterator it = tbl.begin(); it != tbl.end(); ++it) { cout << *it << endl; } return 0; } ======= ここまでソース ============================================= なお、この種の問題 (文字列を文字のパターンで区切ったり、パターンに該当する部分文字列を 検索したりする) は古くから研究されていて、ライブラリも多くあります。 正規表現 もその一つです 正規表現をサポートしたライブラリはたくさんありますので 探してみてください 日本語にきちんと対応した (ex Shift-JISでも"表"という文字と'\'を混乱しない) ものもたくさんあります

voltaire00
質問者

お礼

C++で実装しているため非常に助かります。 おっしゃる通り、strtokを使うやり方では確かに融通が利かないところもありますね。 この方法でも試してみようと思います。ついでに正規表現についても調べてみます。 どうもありがとうございました。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.1

C言語での一例です。 #include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char str[] = "(1,1,4,4,2,3,2,3)"; char *token, *dlm = "(,"; token = strtok(str, dlm); while (token) { printf("%d\n", atoi(token)); token = strtok(NULL, dlm); } return 0; }

voltaire00
質問者

補足

早速の回答ありがとうございます。 試してみます。

関連するQ&A