文字列の前後にある不要な文字列を除去し、
「年月日 日時」だけを取り出したいです。
元となる文字列の例:
2010-03-15 00:00:00 //不要文字が無い状態
2010-03-15 00:00:00 //前や後に全角空白
2010-03-15 00:00:00 //前や後にタブ
2010-03-15 00:00:00#10#13 //前や後に改行が何個もある場合がある。
今は2010-03-15 00:00:00です。 //ある程度想定される文字列を含む。
(2010-03-15 00:00:00) //ある程度想定される文字列を含む。
今は、
while RightStr(strClip, 3) = '#13' do
s := LeftStr(strClip, Length(s) - 3);
というように文字切り出しを何パターンか作っていますが、
あまりスマートでないように思います。
何か、スマートに記述する方法がありましたら、
ぜひ教えていただきたく思います。
どうぞよろしくお願いします。
0〜9、−、:以外は全てStringReplaceで除去し、最後に
日付と時刻の間にスペースを入れるというのはどうでしょう?
頭とお尻からそれぞれ数字が現れるまで削っていくという方針で
例えばこんなのはどうでしょう。
function trim_date(const str: String): String;
var stpos, edpos: Integer;
begin
stpos := 1;
while (stpos <= Length(str)) and not (str[stpos] in ['0'..'9']) do Inc(stpos);
edpos := Length(str);
while (edpos > stpos) and not (str[edpos] in ['0'..'9']) do Dec(edpos);
Result := Copy(str, stpos, edpos - stpos + 1);
end;
「あと15分で2010-03-15 00:00:00になります」みたいに余計な数字が入っていると駄目ですけど。
できれば正規表現で処理が望ましいかと思います(BRegExp.pas)
http://www2.big.or.jp/~osamu/Delphi/MyLibrary.htm
http://oraclesqlpuzzle.hp.infoseek.co.jp/regex/
今サンプル組もうとしましたが、
久しぶり過ぎてやり方忘れてます。。。
参考として見てください。
必要な文字列のみ残すのも一考ですが、torさんの言われるように
「あと15分で・・・」などとなったらだめですね。
ならば、判定用の関数を作っておいて、頭から一文字づつ判定して
いく力技。
手続き上では・・・
(1)頭から一文字づつ調べて、まず数値文字か判定する。
(2)数値文字なら後19文字以上文字列が残っているか判定する。
(3)残っていた場合、19文字分切り出して判定する。
(4)日付文字列なら文字分飛ばしてから、また一文字づつ調べて・・・
(3)の判定関数(めくら打ち)
function XXXXX(切り出した文字列:String):Boolean;
var
i :Integer;
begin
Result := False;
for i = 1 to 19 do
begin
case i of
1..4,6,7,9,10,12,13,15,16,18,19 :
if (切り出した文字列[i] in ['0'..'9']) = False then Breake;
5,8 : if 切り出した文字列[i] <> '-' then Breake;
11 : if 切り出した文字列[i] <> ' ' then Breake;
14,17 : if 切り出した文字列[i] <> ':' then Breake;
end;
end;
Result := True;
end;
perl互換じゃない,思いっきりべたな正規表現で書くとすれば,
ここから→[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]←ここまで
を正規表現で検索すればよいのでは?
コードエディタに
2010-03-15 00:00:00
みたいなのをいくつか入力して,検索してみてください。
正規表現を使いたければ,そこらのエディタでもできるし,正規表現検索
コンポーネントも使いやすいのがいくつか見つかるはずです。
時間表示が YYYY-MM-DD HH:MM:SS の固定なら
私だったらPos関数で '-' or ':' を探し、そこから前に必要な文字数、後ろに必要な文字数をcopy関数で取り出します。
必要があれば、取り出したい文字列に'-' and ':'が入っているか、取り出した文字数が必要文字数になっているかの
チェックもしますが。
澗 さんが発言されないのて、何が望みなのか分かりませんが、
最初のお題からいけば
copy(st,pos('-',st)-4,19);で答えが出ます、最初に-が出るとこけますが。
皆さま、多くのアドバイスをありがとうございました。
そして返信が遅くなり申し訳ありません。
>manbonさん
「0〜9、-、:以外は全て」という識別方法がわかりませんでした(^^;)
>torさん
そうなんですよね、「削る」方法だと余計な文字の混入が怖いです。
>Ruさん
正規表現。
その手法はどうもイメージが付きにくく、避けてしまいます(^^;
習得すべきなんでしょうね...。
>あなたな〜ら、どうする♪さん
なるほど...順に判定していけば良いのですね。
一筋の光が見えてきました。
>あさん
も、もしかして、、、正規表現の答えはそんな簡単なんですか(@@
>3Kさん TSさん
pos関数で場所を見つけて処理する、これは良いですね!
皆さまから頂いたアドバイスを元に、作ってみました。
ひとまず動く事を確認できました。
正規表現については、これから勉強しようと思います。
ありがとうございました。
function TForm1.GetDateTime(sText:string; var sDate , sTime : string):string;
var
sTemp : string;
iTemp,i : integer;
begin
//(0)値の初期化
sDate:='';
sTime:='';
//(1)日付の切り出し
iTemp := pos('-',sText);
if (iTemp>4) and (copy(sText,iTemp+3,1)='-') then //日付と判定
begin
sDate:=copy(sText,iTemp-4,10);
end;
//(2)時刻の切り出し
iTemp := pos(':',sText);
if (iTemp>3) and (copy(sText,iTemp+3,1)=':') then //時刻と判定
begin
sTime:=copy(sText,iTemp-2,8);
end;
//(3)戻り値の生成
if (length(sDate)=0)and(length(sTime)=0) then result:='';
if (length(sDate)=0)and(length(sTime)>0) then result:=sTime;
if (length(sDate)>0)and(length(sTime)=0) then result:=sDate;
if (length(sDate)>0)and(length(sTime)>0) then result:=sDate+' '+sTime;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
sDate , sTime : string;
begin
ShowMessage(GetDateTime(Edit1.Text,sDate , sTime));
ShowMessage(sDate);
ShowMessage(sTime);
end;
取り出したい文字列よりも前に -や:があると取り出せませんね。
そうなってくると、もう、正規表現の世界なんでしょうかね・・・
ひとまず解決とさせていただきます。
皆さま、ありがとうございました。
> その手法はどうもイメージが付きにくく、避けてしまいます(^^;
まぁ、そう言わず... (^^;A
SKRegExp (http://komish.com/softlib/skregexp.htm) でのサンプルです。
uses
..., SKRegExpW;
function ExtractDateTimeStr(const AInputString: String): String;
var
RegExp: TSkRegExp;
begin
result := '';
RegExp := TSkRegExp.Create;
try
RegExp.Expression := '\d{4}[-/][0-1]\d[-/][0-3]\d +[0-2]\d(:[0-5]\d){2}';
if RegExp.Exec(AInputString) then
result := RegExp.Match[0];
finally
RegExp.Free;
end;
end;
※正規表現文字列の解説
\d{4} // 年 (4 桁の数字。数字の 4 回の繰り返し)
[-/] // 日付区切文字 ('-' または '/')
[0-1]\d // 月 (1 桁目は '0' か '1'、2 桁目は数字)
[-/] // 日付区切文字 ('-' または '/')
[0-3]\d // 日 (1 桁目は '0'〜'3'、2 桁目は数字)
+ // 空白の 1 文字以上の繰り返し
[0-2]\d // 時 (1 桁目は '0'〜'2'、2 桁目は数字)
(:[0-5]\d){2} // 分/秒 (時刻区切文字 ':' に続く 1 桁目は '0'〜'5'、2 桁目は数字)
// 分と秒は同じ条件なので 2 回繰り返し
もっといい正規表現があると思われます。イロイロと試してみて下さい。
>DEKOさん
ありがとうございます!(^^)
DEKOさんのお陰で重い腰が上がりました(笑)
この方法で次の2パターンであれば抜き出しできるのですね。
2010/01/01 12:34:56
2010-01-01 12:34:56
これは身につけると強い味方になりますね。
例えば、二桁表示でなく1桁表示の場合、
2010/1/1 1:3:04
こういう時でも正規表現で抜き出せるんですよね?
ヤル気が起きてきました(^-^)
1桁版でも抜き出せるように頑張ってみます。
もし挫折したら、、、その時はまたよろしくお願いします(ペコ
ありがとうございました!!
ひとまず解決処理。
RegExp.Expression := '\d{4}[-/][0-1]?\d[-/][0-3]?\d +[0-2]?\d(:[0-5]?\d){2}';
これで "2010/1/2 3:4:5" も抜き出せるようになります。
※正規表現文字列の解説 (同じトコロは割愛)
[0-1]?\d // 月 (1 桁目は '0' か '1' または 'なし'、2 桁目は数字)
[0-3]?\d // 日 (1 桁目は '0'〜'3' または 'なし'、2 桁目は数字)
[0-2]?\d // 時 (1 桁目は '0'〜'2' または 'なし'、2 桁目は数字)
(:[0-5]?\d){2} // 分/秒 (時刻区切文字 ':' に続く 1 桁目は '0'〜'5' または 'なし'、2 桁目は数字)
// 分と秒は同じ条件なので 2 回繰り返し
# '?' は 0 または、1 回の繰り返しにマッチします。
暫定的な対応ですので、もし適合しないルールがありましたら、適宜追加してお使い下さい。
ヘルプにもあるように、"SKRegExp は Perl 互換" なので、
構文をうろ覚えでも、殆ど Perl の正規表現サンプルのコピペで済むから楽ですよ。
# URL 抜き出しですとか、Mail アドレス抜き出しですとか...。
ツイート | ![]() |