アプリ版:「スタンプのみでお礼する」機能のリリースについて

入力された文字列から整数だけを取り出すにはどうしたらよいのでしょうか?
例えば、

(1,1,4,4,2,3,2,3)

と入力された時、'(' や ',' は無視して、

1 1 4 4 2 3 2 3

のみを取り出したいのですが。。
自分なりにiostreamの関数について調べてみたのですが、良い方法が思いつきません。
どなたかお力添えをお願いいたします。

A 回答 (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 です。
    • good
    • 1
この回答へのお礼

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

お礼日時:2009/04/13 11:23

>#5さん


>※ "整数だけを取り出す"問題

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

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() 使っても良いし、符号("+-")や小数点(".")等も数値同様出力する様する事も可能です。
    • good
    • 0

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」という「-」で繋がっている場合の考慮を
していません。よって「この形が出現しない」という前提でしか使えません。
この点を踏まえた上で参考にして下さい。
    • good
    • 0

こんな感じでどうですか?



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);
}
    • good
    • 1

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でも"表"という文字と'\'を混乱しない)
ものもたくさんあります
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/04/11 14:59

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;
}

この回答への補足

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

補足日時:2009/04/11 08:54
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!