こんにちは、環境は
WinXP VC7 MFC です。
CSV形式のファイルの読み込みで、
CString型のデータでstrtokと同じ様な機能を使用したいのですが。
char型を使わずに出来るのでしょうか?
シリアライズ関数の読み込みのところで
CString cs,data;
ar.ReadString(cs);
data=strtok(cs,,); //ここでCStringからchar*に変換できないといわれます
MessageBox(NULL,data,",MB_OK);
宜しくお願いします
CAVで検索してみたのですがよくわかりませんでした、、
strtok() の動作について理解なさっていれば第一引数に CString の
インスタンスを用いようとは考えないと思いますが、クラス CString の
メンバーについてもう少し注意深く調べてみれば CString::Find() が
こういう目的に使えそうだと分ったのではないかと思うと残念です
strtok() の第一引数は char * ですから、CString に char * への
変換関数が備わっていないに事に注意する必要があります
このことが
>data=strtok(cs,,); //ここでCStringからchar*に変換できないといわれます
事の意味です(キャストして解決できるという事では決してありません)
strtok() の第一引数が const char * ではなく char * なのはそれなりに意味が
あるのです。MSDN ライブラリーで strtok について調べてみましょう
>char型を使わずに出来るのでしょうか?
strtok() の関数定義を見ても分かることですが、strtok() は与えられた文字列バッフ
ァに対して書き込みを行うため、CString との相性はよくありません。
CString に格納された文字列を strtok() で処理したいなら、CString が保持している
文字列を、一度 char 型の配列にコピーして、それを strtok() することになります。
すみません、よくわからないのですが
>const char * ではなく char * なのはそれなりに意味があるのです。
strtokは文字列に\0が埋め込まれるのでconstという事でしょうか、
2バイト文字には使えなさそうな事もなんとなくわかります。
>CString::Find() がこういう目的に使えそう
MSDNでCString::Find()のヘルプがわからなかったので
CStringT::Findというのを見てみました、
CString::Mid()と組み合わせて使えばCOVの,で区切られた文字列を
とりだせそうなのですが、
Find()で文字列の二個目、三個目…にある,のインデックスを知るには
どうすればよいのでしょうか?
最初の,のインデックスは Find(,0)
二個目は Find(,,Find(,,0))
三個目は Find(,,Find(,,Find(,,0)))
とか考えてみたのですがうまくいかないみたいです、、
>最初の,のインデックスは Find(,0)
>二個目は Find(,,Find(,,0))
>三個目は Find(,,Find(,,Find(,,0)))
>とか考えてみたのですがうまくいかないみたいです、、
そのような書き方が出来るのかどうか分らないのでどういうこと
なのかよく分からないのですが、Find() で得た値を用いて次の
カンマの位置が知りたいのだと解釈してみました
CString Sample(_T(,12,456,89));
という例で考えてみましょう
int nPos =Sample.Find(',', 0);
これでは nPos の値は 0 になっているはずですね?
すると
int nPos2 =Sample.Find(',', nPos);
には何が返ってくるでしょうか?
見つけた位置の次から探さなければずーっと同じ所の文字を見つける
だけですね?
こういうことでいいのでしょうか?
ご教授ありがとうございます。
たしかに無意味な事をやってました。
CString cs,data;
int i=0,j=0;
cs=あいうえお,ABC,1234567,あA1,;
data=cs.Mid(0,cs.Find(,,i));
MessageBox(NULL,data,1番目の文字列は,MB_OK);
i=cs.Find(,,i+1);
j=cs.Find(,,i+1);
data=cs.Mid(cs.Find(,,i)+1,cs.Find(,,j)-cs.Find(',',i)-1);
MessageBox(NULL,data,2番目の文字列は,MB_OK);
i=cs.Find(,,i+1);
j=cs.Find(,,i+1);
data=cs.Mid(cs.Find(,,i)+1,cs.Find(,,j)-cs.Find(',',i)-1);
MessageBox(NULL,data,3番目の文字列は,MB_OK);
i=cs.Find(,,i+1);
j=cs.Find(,,i+1);
data=cs.Mid(cs.Find(,,i)+1,cs.Find(,,j)-cs.Find(',',i)-1);
MessageBox(NULL,data,4番目の文字列は,MB_OK);
あとはループ処理で書き直せばやりたかった事はできそうです。
おかしな点があれば御指摘下さい。
.
::AfxExtractSubString(sBuffer, sFromWord, nIndex, ',');
とかを使うと幾分楽です。
ありがとうございます。
書き直してみました
CString cs,data;
cs=あいうえお,ABC,1234567,あA1,;
AfxExtractSubString(data,cs,0,',');
AfxMessageBox(data);//一番目の文字列
cs=cs.Right(cs.StringLength(cs)-data.StringLength(data)-1);
AfxExtractSubString(data,cs,0,',');
AfxMessageBox(data);//二番目の文字列
cs=cs.Right(cs.StringLength(cs)-data.StringLength(data)-1);
AfxExtractSubString(data,cs,0,',');
AfxMessageBox(data);//三番目の文字列
cs=cs.Right(cs.StringLength(cs)-data.StringLength(data)-1);
AfxExtractSubString(data,cs,0,',');
AfxMessageBox(data);//四番目の文字列
おかしな点があれば御指摘下さい。
それと本題からそれるのですが
AfxExtractSubStringをMSDNで見つけられなかったのですが
探し方が悪かったのでしょうか?
AfxExtractSubStringの三番目の引数は何番目の文字列を持ってくるか
という意味で、0から始まるインデックスです。
だから、例えばカンマ区切りの文字列
CString cs(ABC,DEF,GHI,JKL);
1番目の文字列(ABC)
CString dataに格納したい場合は
AfxExtractSubString(data, cs, 0, ',');
とし、
から2番目の文字列(DEF)を取り出して
CString dataに格納したい場合は
AfxExtractSubString(data, cs, 1, ',');
とします。
ちなみにAfxExtractSubStringはMSDNでは解説されていません。
Microsoftのサイトでは未確認ですが。
ごめんなさいぃぃ。文章がぐちゃぐちゃ。
正しくは↓です。
AfxExtractSubStringの三番目の引数は何番目の文字列を持ってくるか
という意味で、0から始まるインデックスです。
だから、例えばカンマ区切りの文字列
CString cs(ABC,DEF,GHI,JKL);
から1番目の文字列(ABC)を取り出して
CString dataに格納したい場合は
AfxExtractSubString(data, cs, 0, ',');
とし、
2番目の文字列(DEF)を取り出して
CString dataに格納したい場合は
AfxExtractSubString(data, cs, 1, ',');
とします。
ありがとうございます。
三番目の引数は文字列の先頭からのインデックスだとばかり思ってました。
勉強になります。
>ちなみにAfxExtractSubStringはMSDNでは解説されていません。
>Microsoftのサイトでは未確認ですが。
Webのほうでも見当たらないようですね。
こんなに便利な関数を解説してないとは…
あまり良くないけど、strtokの機能が必要になって作ったクラスです。
かなりへぼいですが、参考に…なるのかなぁ(;´Д`)
一応、インスタンスを作ることで、strtokでは static char * を返すという
問題を調整しています。
RtlToken tok(_T(ABC,DEF,GHI, ,);
CString strSub = tok.GetNextToken();
という風に使います。
# Perlのように、split が使えればいいのに(--;
// strtok のクラス実装
class RtlToken
{
protected:
// Members
CString m_strText;
CString m_strSep;
public:
// Ctor/Dtor
RtlToken(LPCTSTR lpszText = _T("), LPCTSTR lpszSeparator = _T
( )) : \
m_strText(lpszText), m_strSep(lpszSeparator)
{
}
~RtlToken()
{
m_strText.Empty();
m_strSep.Empty();
}
void operator()(LPCTSTR lpszText = _T("), LPCTSTR lpszSeparator = _T
( ))
{
m_strText = lpszText;
m_strSep = lpszSeparator;
}
void operator=(LPCTSTR lpszText)
{
m_strText = lpszText;
}
void SetSeparator(LPCTSTR lpszSeparator = _T( ))
{
m_strSep = lpszSeparator;
}
// Operations
// 参照されていない残り部分を返し、バッファをクリアする
CString GetRestString()
{
CString strRet = m_strText;
m_strText.Empty();
return strRet;
}
// 一度使用した文字列と直後の区切り文字列は削除する
CString GetNextToken()
{
ATLASSERT( !m_strSep.IsEmpty() );
CString strRet = m_strText;
if (m_strSep.IsEmpty()) {
m_strText.Empty();
return strRet;
}
const int nPos = strRet.Find(m_strSep);
if (nPos >= 0)
strRet = strRet.Left(nPos);
// standby for next call
const int nLen = strRet.GetLength();
if (nLen >= 0)
m_strText.Delete(0, m_strSep.GetLength() + nLen);
return strRet;
}
};
とても参考になります。
見慣れないマクロとかあるので調べてみます、
ありがとうございました。