[表示 : 全て 最新50 1-99 101- 201- 301- 401- 501- 601- 2chのread.cgiへ]
Update time : 02/07 11:17 / Filesize : 190 KB / Number-of Response : 625
[このスレッドの書き込みを削除する]
[+板 最近立ったスレ&熱いスレ一覧 : +板 最近立ったスレ/記者別一覧] [類似スレッド一覧]


↑キャッシュ検索、類似スレ動作を修正しました、ご迷惑をお掛けしました

Delphi初心者のための寺子屋



1 名前:デフォルトの名無しさん mailto:sage [2005/11/23(水) 23:31:08 ]
Delphi初心者が問題をコツコツと解きながらレベルアップするためのスレです。


2 名前:デフォルトの名無しさん mailto:sage [2005/11/23(水) 23:38:37 ]
糞スレたてんな。
Delphi関連のスレがいくつあると思ってんだ?
既存のスレを利用しろ池沼


/*          終了          */

3 名前:デフォルトの名無しさん [2005/11/23(水) 23:58:22 ]
早く、問題出せ
俺はやらないが…

4 名前:デフォルトの名無しさん mailto:sage [2005/11/24(木) 00:57:02 ]
そもそもDelphiのスレなんて必要ねーよ
糞言語氏ね

5 名前:デフォルトの名無しさん mailto:sage [2005/11/24(木) 01:36:10 ]
object pascalをいじめないでください><

6 名前:デフォルトの名無しさん mailto:sage [2005/11/24(木) 02:51:06 ]
Dr.Dのマシン語寺子屋ってコーナーがあったなあ・・・・

7 名前:デフォルトの名無しさん [2005/11/24(木) 09:28:17 ]
Unicodeはどうやって扱えますか?

8 名前:デフォルトの名無しさん [2005/11/24(木) 09:56:47 ]
さあ!私にDelphiを教えなさい!

9 名前:デフォルトの名無しさん mailto:sage [2005/11/24(木) 10:34:28 ]
前スレより問題文を転載

//ここから問題文
次は、例外処理の締めとしてRaiseを使おう。
ファイルが開けないときは
writeln(filename)した後、今の例外処理(Writeln(E.Message);)
を実行するように、
また、読み込みエラーのときは、E.Messageの内容を
"読み込めねー"
に変更してみてみてくれ。どちらも Raise を使えば簡単にできる。
//ここまで問題文


10 名前:デフォルトの名無しさん mailto:sage [2005/11/24(木) 10:34:51 ]
ちなみにこのプログラムに手を加えろという問題です

const
    filename='test.txt';
var
    sum:    double;
    fp:    TextFile;
    str:    string;
begin
    sum:=0;
    try
        AssignFile(fp, filename);
        Reset(fp);
        try
            while (not Eof(fp)) do
            begin
                Readln(fp, str);
                sum:=sum+StrToFloatDef(str, 0);
            end;
            writeln(FloatToStr(sum));
        finally
            CloseFile(fp);
        end;
    except
        on E: Exception do Writeln(E.Message);
    end;
end.




11 名前:デフォルトの名無しさん mailto:sage [2005/11/24(木) 10:36:03 ]
現在の回答

sum:=0;
try
  AssignFile(fp, filename);
  try
    Reset(fp);
  except
    Memo1.Lines.Add(filename);
    raise;
  end;
  try
    while (not Eof(fp)) do
    begin
      try
        Readln(fp, str);
      except
        raise Exception.Create('よみこめねー');
      end;
      sum:=sum+StrToFloatDef(str, 0);
    end;
    Memo1.Lines.Add(FloatToStr(sum));
  finally
    CloseFile(fp);
  end;
except
  on E: Exception do Memo1.Lines.Add(E.Message);
end;


12 名前:デフォルトの名無しさん [2005/11/27(日) 18:53:41 ]
次の問題まだぁ〜?

13 名前:デフォルトの名無しさん mailto:sage [2005/11/27(日) 21:46:37 ]
>>11

これで例外処理関係はOKだと思うがどうだろう?

それでは次は文字列処理かな。
入力された文字列から'='を探し出し、
(=より前の文字列)'は、'(=より後ろの文字列)'です。'
という出力、および、処理にかかった時間を出力
するプログラムを作ってみてくれ。


14 名前:デフォルトの名無しさん mailto:sage [2005/11/28(月) 00:18:18 ]
いいかげん自作自演うざいんですけど…

15 名前:デフォルトの名無しさん mailto:sage [2005/11/28(月) 02:18:02 ]
>>14
レスアンカーつけないと誰に言ってるんだか分かりませんよd(^-^)b

16 名前:デフォルトの名無しさん mailto:sage [2005/11/28(月) 03:09:04 ]
つまり、>>13は高速に文字列の中から
'='の左と右を分けたいわけね。


17 名前:デフォルトの名無しさん mailto:sage [2005/11/28(月) 03:31:56 ]
自演乙

18 名前:デフォルトの名無しさん mailto:sage [2005/11/28(月) 16:40:00 ]
>>13
program Project1;

{$APPTYPE CONSOLE}

uses
    SysUtils, Types, MMSystem;

const
    str='Delphi=399,000YEN';

var
    i:    Integer;
    len:    Integer;
    StartTime:    DWORD;
    EndTime:    DWORD;

begin
    StartTime:=timeGetTime;
    i:=1;
    while str[i]<>'=' do
    begin
        Write(str[i]);
        Inc(i);
    end;

    Write('は');
    Inc(i);

19 名前:デフォルトの名無しさん [2005/11/28(月) 16:40:36 ]
    len:=Length(str);
    while i<=Len do
    begin
        Write(str[i]);
        Inc(i);
    end;

    Writeln('です');

    EndTime:=timeGetTime;

    Writeln(Format('タイムは%d_秒です', [EndTime-StartTime]));
    Readln;
end.

//ここまで。よろしくお願いします。

20 名前:デフォルトの名無しさん mailto:sage [2005/11/28(月) 23:16:12 ]
>>18-19
題を出したのとは別人だけども。

・題意は、入力文字列は固定ではなくReadLnで実行時に入力させることを意図していたと思われる。のでReadLnを使う。
・また、'='が見つからなかった場合の処理。
・ふたつめのwhileループは、ループ回数がループ開始前にわかっている。こういう場合は定石としてはforを使う。
・DelphiっぽくNowとTDateTimeを使ってみよう。

ていうかこのスレでいきなりtimeGetTime見て驚いた。



21 名前:デフォルトの名無しさん mailto:sage [2005/11/28(月) 23:20:21 ]
ついでに>>10は、
PascalとしてはDoubleじゃなくRealのほうがいいね。
Delphiだとどっちでも同じ(64ビット倍精度浮動小数点)だけど。

…ちなみに精度が欲しければExtended(80ビット拡張精度)を使う、つーか
Delphiは浮動小数点の内部計算全部Extendedでやってるので、
実はExtendedで統一した方が変換ロスとか無くていい。


22 名前:デフォルトの名無しさん mailto:sage [2005/11/29(火) 09:01:26 ]
>>20
program Project1;

{$APPTYPE CONSOLE}

uses
    SysUtils;

var
    i, j:    Integer;
    len:    Integer;

    StartTime: TDateTime ;
    EndTime: TDateTime ;

    Hour, Min, Sec, MSec: Word;

    str:    String;
begin

    Readln(str);

    StartTime:=Now;

    len:=Length(str);

    i:=1;
    while str[i]<>'=' do
    begin
        Write(str[i]);
        Inc(i);

23 名前:デフォルトの名無しさん [2005/11/29(火) 09:02:09 ]
        if i>len then
        begin
            Writeln;
            Writeln('=が見つかりませんでした');
            Readln;
            Exit;
        end;
    end;

    Write('は');
    Inc(i);

    for j:=i to len do
    begin
        Write(str[j]);
    end;

    Writeln('です');
    EndTime:=Now;

    DecodeTime(EndTime-StartTime, Hour, Min, Sec, MSec);
    Writeln(Hour,'時間',Min,'分',Sec,'秒',MSec);

    Readln;
end.
//ここまで。よろしくお願いします。

24 名前:デフォルトの名無しさん mailto:sage [2005/11/29(火) 09:32:44 ]
>>22

ただ、次の点をアップデートしていただけるとうれしい。
・文字列処理の習得を中心に考えているので結果(XはYです)の出力はまとめて
 行うようにしてほしい。
・Delphi初心者がいきなりコンソールアプリから入るとは考えにくいので
 できればGUIでお願いしたい。
・こちらではコンパイルして確認するわけではないのでコードすべてをアップする
 必要はない(そのため細かいバグは見落としますがそれはゴメン)

25 名前:デフォルトの名無しさん mailto:sage [2005/11/29(火) 10:19:21 ]
DelphiでINIファイルの読み書きをしたいのですが・・
良いサンプルとかありませんでしょうか?

26 名前:デフォルトの名無しさん mailto:sage [2005/11/29(火) 11:00:56 ]
>>25
ヘルプでTIniFileを検索して、あとは色々たどっていけばサンプルがあるけど、それじゃダメか?

27 名前:デフォルトの名無しさん mailto:sage [2005/11/29(火) 12:13:12 ]
>>26
TIniFile検索してみたけどちょっとわかりずらいっす。
でもTIniFileを使うってのがわかったので助かります。
さんくす

28 名前:デフォルトの名無しさん mailto:sage [2005/11/29(火) 18:30:10 ]
>>22-23 & >>24
空文字列が入力されたら存在しないstr[1]をアクセスしにいかないか?

29 名前:デフォルトの名無しさん [2005/11/29(火) 18:48:21 ]
>>28
    if len=0 then
    begin
        exit;
    end;

修正しました

30 名前:デフォルトの名無しさん mailto:sage [2005/11/29(火) 20:52:30 ]
>>27
D7だとヘルプのテキスト検索で「TIniFile とTMemIniFile の使い方」
ここにサンプル載ってるけどダメか?

ちょっとコード書いてみて、具体的にわからない所があったら質問してみ。



31 名前:デフォルトの名無しさん [2005/11/30(水) 13:05:59 ]
メディアンフィルタとかガンマが付いてるTImageの派生クラスはありまつか?

32 名前:デフォルトの名無しさん mailto:sage [2005/11/30(水) 17:12:15 ]
>>24
結果をまとめて表示、GUIをやりました
よろしくお願いします

procedure TForm1.Button1Click(Sender: TObject);
var
    i, j:        Integer;
    len:        Integer;

    StartTime: TDateTime ;
    EndTime: TDateTime ;

    Hour, Min, Sec, MSec: Word;

    str_src:    String;
    str_dest: String;
begin
    str_src:=Edit1.Text;
    StartTime:=Now;
    len:=Length(str_src);

    if len=0 then
    begin
        ShowMessage('なにか文字を入力してください');
        exit;
    end;

    i:=1;
    while str_src[i]<>'=' do
    begin
        str_dest:=str_dest+str_src[i];
        Inc(i);

33 名前:デフォルトの名無しさん [2005/11/30(水) 17:12:50 ]
        if i>len then
        begin
            ShowMessage('=が見つかりませんでした');
            Exit;
        end;
    end;

    str_dest:=str_dest+'は';
    Inc(i);

    for j:=i to len do
    begin
            str_dest:=str_dest+str_src[j];
    end;

    str_dest:=str_dest+'です';
    EndTime:=Now;

    DecodeTime(EndTime-StartTime, Hour, Min, Sec, MSec);
    Memo1.Lines.BeginUpdate;
    Memo1.Lines.Add(str_dest);
    Memo1.Lines.Add(Format('%u時間 %u分 %u秒 %u', [Hour,Min,Sec,MSec]));
    Memo1.Lines.EndUpdate;
end;
//ここまで

34 名前:デフォルトの名無しさん mailto:sage [2005/11/30(水) 20:35:52 ]
>>32


文字列処理は大丈夫っぽいのでまとめてお題を出しちゃおう。
1 Pos(AnsiPos)関数を使ってみる
2 その他使えそうな標準関数がないか探して使ってみる
3 PCharを使ってみる

35 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 02:33:50 ]
>>34
あんたホントに理解してんの?

36 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 09:24:06 ]
>>35
日本語処理のことかな。
そこは出題意図ではないので別の機会で勉強してくれ。


37 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 10:18:01 ]
日本語処理を無視した文字列処理はナンセンス

38 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 10:23:44 ]
>>37
ごめんな。
俺だけがお題を出すのも限界があるから是非もっとよいお題を頼む。

39 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 10:42:02 ]
お題
「このスレの1−38までを Memo1 にコピーして、「Delphi」という文字列が何度
現れたか数えなさい。

40 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 14:08:14 ]
>>34の1
begin
    str_src:=Edit1.Text;
    StartTime:=Now;

    len:=Length(str_src);
    eq_pos:=pos('=', str_src);

    if len=0 then
    begin
        ShowMessage('なにか文字を入力してください');
        exit;
    end;
    if eq_pos=0 then
    begin
        ShowMessage('=が見つかりませんでした');
        Exit;
    end;

    str_dest:=copy(str_src, 1, eq_pos-1);
    str_dest:=str_dest+'は';
    str_dest:=str_dest+copy(str_src, eq_pos+1, High(Integer));
    str_dest:=str_dest+'です';

    EndTime:=Now;
    DecodeTime(EndTime-StartTime, Hour, Min, Sec, MSec);
    Memo1.Lines.BeginUpdate;
    Memo1.Lines.Add(str_dest);
    Memo1.Lines.Add(Format('%u時間 %u分 %u秒 %u', [Hour,Min,Sec,MSec]));
    Memo1.Lines.EndUpdate;
end;



41 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 14:26:49 ]
>>34の2

回答1.DeleteとInsertを使う
Delete(str_src, eq_pos, 1);
Insert('は', str_src, eq_pos);
str_dest:=Concat(str_src, 'です');

回答2.出来合いの関数を使う
Borland - Delphi Q&A 文字列を一括置換するには
www.borland.co.jp/qanda/delphi/d0005103.html

回答3.正規表現を使う
TRegExpr - PukiWiki
onigiri.s3.xrea.com:8080/delphi/index.php?TRegExpr

※2と3は標準関数ではないですが見つけたので添えておきます

42 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 17:43:03 ]
D5 以降だと StringReplace があるけど

43 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 18:24:52 ]
>>42
天才あらわる

44 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 22:23:51 ]
>>34の3
    PSrc:=AllocMem(len+1);
    PSrcCopy:=PSrc;
    ZeroMemory(PSrc, len+1);

    for i:=1 to len do
    begin
        PSrc[i-1]:=str_src[i];
    end;

    while PSrc^ <> #0 do
    begin
        if PSrc^ = '=' then
        begin
            str_dest:=str_dest+'は';
        end
        else
        begin
                str_dest:=str_dest+PSrc^;
        end;
        Inc(PSrc);
    end;
    str_dest:=str_dest+'です';
    FreeMem(PSrcCopy, len+1);

45 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 22:41:39 ]
メモリ割り当ててコピーは無駄。ポインタ使う意義が半減。

PSrc := PChar(str_src);

でいいんでない?

46 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 23:10:52 ]
>>45
了解です。修正しました。
PCharとStringの変換が意外と楽で感激
    PSrc:=PChar(str_src);
    while PSrc^ <> #0 do
    begin
        if PSrc^ = '=' then
        begin
            str_dest:=str_dest+'は';
        end
        else
        begin
                str_dest:=str_dest+PSrc^;
        end;
        Inc(PSrc);
    end;
    str_dest:=str_dest+'です';

47 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 23:13:41 ]
>>39
    p:=0;
    cnt:=0;
    str:=Memo1.Text;
    len:=length(sword);

    repeat
        ap:=Pos(sword, copy(str, p, High(Integer)));
        if ap>0 then
        begin
            p:=p+ap;
            Inc(cnt);
            Inc(p, len);
        end;
    until ap=0;
    ShowMessage(IntToStr(cnt));

48 名前:デフォルトの名無しさん [2005/12/01(木) 23:32:47 ]
>>39をPCharを使って解きました
文字列の添え字に間違って0を使ってしまってハマってしまいました
PCharのときは0から、それ以外(constやstring)は1からでいいんですよね?
    p:=1;
    cnt:=0;
    str:=Memo1.Text;
    PStr:=PChar(str);
    len:=length(sword);

    while PStr^ <> #0 do
    begin
        if PStr^ = sword[p] then
        begin
            Inc(p);
            if (p=len) then
            begin
                Inc(cnt);
                p:=1;
            end;
        end
        else
        begin
            p:=1;
        end;
        Inc(PStr);
    end;
    ShowMessage(IntToStr(cnt));

49 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 23:32:52 ]
>>47
パチパチパチ、すばらしい
◎-3

減点は、この場合は問題ないだろうけど、日本語処理では Pos じゃなく AnsiPos
を使うこと。

いろいろ改良点があるけど

ap:=Pos(sword, copy(str, p, High(Integer)));

これがこの処理のキモ。でも、文字列コピーは最も効率悪い方法。
1MByte のテキストで検索文字列が1000回現れたら、1000回コピーする
ことになる。PChar をつかってなるべくコピーをしないで処理する方法を
考えるのが次のお題。



50 名前:デフォルトの名無しさん mailto:sage [2005/12/01(木) 23:34:57 ]
> PCharのときは0から、それ以外(constやstring)は1からでいいんですよね?

そう。string 型は、パルカルのときの実装を引きずっていますので例外的に1から、と覚える




51 名前:デフォルトの名無しさん mailto:sage [2005/12/02(金) 00:00:42 ]
×パルカル
○パスカル

52 名前:デフォルトの名無しさん mailto:sage [2005/12/02(金) 00:06:33 ]
49 のヒント AnsiStrPos

53 名前:デフォルトの名無しさん [2005/12/02(金) 09:07:30 ]
TEditに英文字のみ入るようにする方法教えて下さい。

54 名前:53 [2005/12/02(金) 09:19:30 ]
イベントハンドラでキー入力をカット出来ないかなぁ?

55 名前:デフォルトの名無しさん mailto:sage [2005/12/02(金) 09:35:55 ]
>39にも誰か答えてやれよ

56 名前:デフォルトの名無しさん mailto:sage [2005/12/02(金) 09:38:03 ]
×39
○31

57 名前:デフォルトの名無しさん mailto:sage [2005/12/02(金) 09:58:38 ]
> Delphi初心者が問題をコツコツと解きながらレベルアップするためのスレです。

単発質問はくだすれへ

58 名前:デフォルトの名無しさん mailto:sage [2005/12/02(金) 16:42:41 ]
>>48

Inc(p);
if (p=len) then

これじゃ、比較が一バイト少ないよ。それから、2バイト文字を考慮してないので
ダメです。「Delphi」ならまず問題ないけど「D」だったら、2バイト文字の2バイト目も
数えてしまう可能性がある。


59 名前:デフォルトの名無しさん [2005/12/05(月) 21:38:25 ]
>>49
日本語処理にも気をつけました
よろしくお願いします。

const
    sword='Delphi';
var
    str:    AnsiString;
    cnt:    Integer;
    PStr: PChar;
begin
    cnt:=0;
    str:=Memo1.Text;
    PStr:=PChar(str);

    repeat
        PStr:=AnsiStrPos(PStr, sword);
        if (PStr<>nil) then
        begin
            if (StrByteType(PStr, 0)=mbSingleByte) then
            begin
                Inc(cnt);
            end;
            Inc(PStr);
        end;
    until PStr=nil;

    ShowMessage(IntToStr(cnt));

end;


60 名前:デフォルトの名無しさん mailto:sage [2005/12/06(火) 00:37:50 ]
>>59
AnsiStrPosを使ってる時点で2バイト文字として意味のある位置で
結果が返ってる筈なんでStrByteTypeいらない。

というか前からスキャン方式でStrByteTypeは使っちゃだめ。
途中の位置をいきなり指定してそれがどこにあたるか調べるのは
前後の文字を辿るしかなく、
逆にそういった機能を持つ関数を使うことは
その次点に到達するまで前からスキャンしてきたこと自体を
無駄にしてる。
前から辿るならAnsi〜系を使わずに自力でマルチバイト処理をするとしても
LeadBytesで充分。



61 名前:デフォルトの名無しさん mailto:sage [2005/12/06(火) 00:46:30 ]
>>59

惜しい。あと一歩。78点くらい。
たぶん結果は正しい。冗長なのが減点の原因。

AnsiStrPos は二バイト文字をサポートしていますので、検索の先頭を間違わなければStrByteType による確認は不要です。

それから、見つかったら、PStr は検索文字列の長さ分だけ Inc() してから再度検索します。

    repeat
        PStr:=AnsiStrPos(PStr, sword);
        if (PStr<>nil) then
        begin
          Inc(cnt);
          Inc(PStr, Length(sword));
        end;
    until PStr=nil;

このようにすると検索文字列が 「Delphi」であっても「デルファイ」であっても問題なく検索できます。
>>59 の回答は検索文字列の最初が一バイト文字であることを仮定しているので正しくないです。

しかし、かなりな進歩で驚いています。

次のお題は、何回現れるかの他に、その位置も返すような関数をつくってください。具体的には、RichEdit に
同様にテキストを読み込んで、ボタンを押すと Delphi の部分が赤い文字列になるようにします。

赤文字にする方法、位置情報を返すための配列の定義の仕方など、分からないことがあったら個別に質問してください。

62 名前:デフォルトの名無しさん [2005/12/07(水) 01:04:33 ]
>>61
begin
    cnt:=0;
    spos:=0;

    str:=RichEdit1.Text;
    PStr:=PChar(str);
    len:=Length(sword);

    repeat
        p:=AnsiPos(sword, PStr+spos);

        if (p>0) then
        begin
            Inc(cnt);
            Inc(spos, p);

            with RichEdit1 do
            begin
                SelStart:=spos-1;
                SelLength:=len;
                SelAttributes.Color:=clRed;
            end;
            Inc(spos, len);

        end;

    until p=0;
    ShowMessage(IntToStr(cnt));
end;
//ここまで
よろしくお願いします。

63 名前:デフォルトの名無しさん mailto:sage [2005/12/07(水) 02:35:14 ]
>>62
AnsiPosに暗黙のPChar→String変換で引数渡してるよね…。
これは暗黙に実行されるわりにコストがメチャ高いので、
ループの中では避けたほうがいい。
上と同じでAnsiStrPosじゃダメだったの?

64 名前:デフォルトの名無しさん mailto:sage [2005/12/07(水) 03:05:54 ]
>>62

すばらしい!

つぎに、汎用的に使えるように関数にしてみてください。

type
TPosArray = array of integer;

function SearchAndPos(const SubStr, Str: string; PosArray: TPosArray): integer;

で戻り値が出現回数であるような。>>63 さんのおっしゃるとおり、AnsiStrPos をつかって
実装してみてください。

65 名前:デフォルトの名無しさん mailto:sage [2005/12/07(水) 03:10:21 ]
すみません、関数は

function SearchAndPos(const SubStr, Str: string; var PosArray: TPosArray): integer;

の形です。var をわすれました。

66 名前:デフォルトの名無しさん [2005/12/09(金) 04:07:45 ]
>>64-65
AnsiStrPosを使うように変更しました
よろしくお願いします

function SearchAndPos(const SubStr, Str: string; var PosArray: TPosArray): integer;
var
    PStr:     PChar;
    PBgmStr:    PChar;
    PSubStr:    PChar;
    Cnt:    Integer;
    Len:    Integer;
begin
    Cnt:=0;
    Len:=Length(SubStr);

    PBgmStr:=PChar(Str);
    PStr:=PBgmStr;
    PSubStr:=PChar(SubStr);

    repeat
        PStr:=AnsiStrPos(PStr, PSubStr);
        if (PStr<>nil) then
        begin
            Inc(Cnt);
            SetLength(PosArray, Cnt);
            PosArray[Cnt-1]:=PStr-PBgmStr;
            Inc(PStr, Len);
        end;
    until PStr=nil;

    result:=Cnt;
end;

67 名前:デフォルトの名無しさん mailto:sage [2005/12/09(金) 09:57:48 ]
>>66

すばらしい!
実際のの動作はすみませんが、時間が出来たらあとで検証してみます。
見た限りでは問題無さそうです。

>>47 から比べると格段の進歩です。検索には一度も文字列コピーをしてないのですよね。

今回の教訓は、ひとかたまりの論理が完結したら、関数や手続き、クラス内のメソッド
などで表現すべき、ということです。コードの断片より、関数などで完結した論理を
表現しておくと、たとえ他の言語や環境になったとしても論理そのものは生きるので
自分の財産にすることが出来ます。

68 名前:デフォルトの名無しさん mailto:sage [2005/12/09(金) 09:58:14 ]
次の課題。

1)Delphi には Pos や AnsiPos にように文字列の先頭から、最初の位置までを
検索する関数がありますが、途中から検索する関数がありません。それを

function AnsiPosEx(const Substr, S: string; initPos: integer): Integer;

の形で AnsiStrPos をつかって、つくってください。そして、それをつかって >>66
書き直してみてください。

2)>>66 では見つかるたびに SetLength() を使って配列を一つずつ増やしています。
これは非効率的なので、たとえば10個づつ増やすようにしてみてください。

69 名前:デフォルトの名無しさん mailto:sage [2005/12/09(金) 20:18:26 ]
>>68
function AnsiPosEx(const SubStr, S: string; initPos: integer): Integer;
var
    PSubStr:    PChar;
    PS: PChar;
    PBgn: PChar;
    PPos: PChar;
begin
    PSubStr:=PChar(SubStr);
    PS:=PChar(S);
    PBgn:=PS+initPos;

    PPos:=AnsiStrPos(PBgn, PSubStr);
    result:=PPos-PS+1;
    if result<0 then
    begin
        result:=0;
    end;
end;


70 名前:デフォルトの名無しさん [2005/12/09(金) 20:19:15 ]
function SearchAndPos(const SubStr, Str: string; var PosArray: TPosArray): integer;
var
    PStr:     PChar;
    Cnt:    Integer;
    NowPos: Integer;
    Len:    Integer;
begin
    Cnt:=0;
    NowPos:=0;
    Len:=Length(SubStr);
    PStr:=PChar(Str);

    repeat
        NowPos:=AnsiPosEx(SubStr, PStr, NowPos);
        if NowPos<>0 then
        begin
            if Length(PosArray)=Cnt then
            begin
                SetLength(PosArray, Cnt+10);
            end;
            PosArray[Cnt]:=NowPos-1;
            Inc(Cnt);
            Inc(NowPos, Len);
        end;
    until NowPos=0;
    SetLength(PosArray, Cnt);
    result:=Cnt;
end;
//ここまで

よろしくお願いします



71 名前:デフォルトの名無しさん mailto:sage [2005/12/09(金) 22:22:06 ]
>>69

完璧!! -2 点 =98点

減点は、AnsiPosEx の第二引数に PChar を使ったこと。const の string 型は
呼び出しても、関数内で変更できないのでコピーされることはないです。ですから
string 型のまま使ってください。AnsiPosEx をつくったことにより、SearchAndPos
から、ポインタをあらわにつかうコードが完全になくすることができたことに注目してください。

次の課題は少し難易度が上がります。

このスレの1−38までのテキストのうち、半角の数字がでてきた数を数える関数をつくってください。

いままで、テキスト内の走査は、AnsiPos や AnsiStrPos をつかったのであらわに
コードを書かなかった。この課題では、一バイト文字、二バイト文字を判別しながら
数字かどうかを判定する必要があります。自分のコードでテキストを走査してください。
出来れば、前回のように、文字列の途中から検索して、最初の数字を見つける関数を
つくり、それを使って出現数を数えてください。

72 名前:デフォルトの名無しさん mailto:sage [2005/12/09(金) 22:25:23 ]
ヒント >>60 さんのコメントが参考になります。

73 名前:デフォルトの名無しさん mailto:sage [2005/12/10(土) 00:15:52 ]
数字は全角文字の二バイト目に出てこないよ。


74 名前:デフォルトの名無しさん mailto:sage [2005/12/10(土) 02:07:03 ]
>>73
ありがとう。
ほんとうですね。いま shift-jis のコード表を見ましたら、二バイト文字の二バイト目は
$40 からなんですね。一方 0-9 は $30-$39 ですから、重複しませんね。

うーむ、それでは課題が破綻するので変えることにします。

このスレの1−38までのテキストのうち、半角のアルファベット( a-z と A-Z )文字がでてきた数を数える関数をつくってください。

とします。すみませんでした。

75 名前:デフォルトの名無しさん [2005/12/11(日) 22:32:44 ]
嘘か真かわからんが、QualityCentralにQC#21940で、「Delphi2006 ハング」との事です。時々、ハングアップするとの事です。んー。今まで、Qualityを無視しつづけたツケだな。 -- 2005-12-07 05:54:52 (水) New

2005なんか 最初 吹っ飛んで消滅していたじゃん。 消滅からハングに 大差ないしおどろくことではないかと  先行バグ取り隊の情報引き続きよろしく  -- 2005-12-07 09:14:09 (水) New

>「消滅からハングに 大差ないしおどろくことではない」 どっちにしろ、真面目につかうものではなさそうですね。

「どっちにしろ、真面目につかうものではなさそうですね」 しらずに2005のときせっかく数時間かけて書いたコードが消滅して悲しい思いしたよ -- 2005-12-07 15:22:52 (水) New

76 名前:デフォルトの名無しさん [2005/12/15(木) 07:29:16 ]
>>74
function CountAlpha(var str:    AnsiString):    Integer;
var
    i:    Integer;
    cnt:    Integer;
begin
    cnt:=0;
    i:=0;

    while (i <= Length(str)) do
    begin
        if ( (str[i] in LeadBytes)) then
        begin
            Inc(i,2);
        end
        else
        begin
            if (str[i] in ['a'..'z']) or (str[i] in ['A'..'Z']) then
            begin
                Inc(cnt);
            end;
            Inc(i);
        end;

    end;
    result:=cnt;
end;
//ここまで
よろしくお願いします

77 名前:デフォルトの名無しさん mailto:sage [2005/12/15(木) 10:26:25 ]
>>76
すばらしい! 94点

減点は
CountAlpha(var str: AnsiString): → CountAlpha(const str: AnsiString):

const にして、関数内で変更しない(コピーされない)ことを保証し、
IntToStr(CountAlpha(Memo1.Text)) などと、変数を確保しなくても使えるように
することは重要です。var だと str := Memo1.Text; IntToStr(CountAlpha(str))
などとしなければ使えませんね。

減点ではないけど

if (str[i] in ['a'..'z']) or (str[i] in ['A'..'Z']) then

の部分は

if (str[i] in ['A'..'Z','a'..'z']) then

とすることもできます。

文字列のインデックスは1から始まります。ですから

i:=0; ではなく、 i:=1;

で初期化してください。次の課題は少し事前に検証してから出します。




78 名前:デフォルトの名無しさん mailto:sage [2005/12/15(木) 10:42:34 ]
>>76

つぎの課題は、もうちょっと難易度が上がります。
前回同様、アルファベットの文字を見つけるのは同じですが、塊として数えてください。

例えば

This is a pen.

の場合は4を返すような関数をつくってください。アルファベット以外の文字(空白も含む)で
区切られたアルファベットだけで出来ている語句の数を数えます。

「...ことを保証し、IntToStr(CountAlpha(Memo1.Text)) などと、変数を確保しなくても使えるように」

の場合は、「IntToStr」「CountAlpha」「Memo」「Text」の4つです。

79 名前:デフォルトの名無しさん mailto:sage [2005/12/15(木) 11:52:06 ]
ヒント
新幹線で東京から名古屋まで行くときのトンネルの数を数えるのと同等です。
トンネルの入り口を数えるといいですね。でも入り口を認識するためには
出口を認識する必要があります。出口を認識するためには、「いまトンネルの
なかにいる」という<状態>を変数に保存しておかなければなりません。また、
トンネルの中にも駅があることを考慮しなければなりません。ですから、名古屋
は違いますが終点がトンネルの中の場合もありえます。

80 名前:デフォルトの名無しさん mailto:sage [2005/12/15(木) 12:22:11 ]
すみません(こればっかり)、ヒントの最後の2行は、見つかった語句の長さを
記録するときのものです。今回は無視してください。入り口の数だけで十分です。



81 名前:デフォルトの名無しさん [2005/12/16(金) 13:56:59 ]
●問題2
エディットボックス(Edit1)に入力した数字までの合計値を、ボタン(Button1)を押したら、表示(Label1に表示)させよ。
なお変数は、エディットボックスの入力値(a)、合計値(Sum)、ループのカウンタ(i)とする。

procedure TForm1.Button1Click(Sender: TObject);
var
i,Sum:□□□□□□□;
a:integer;
begin
a:=StrToInt(Edit1.text);
Sum:=0;

for i:= □ to □ do
begin
Sum:= □□□+□
end;

Label1.Caption:=IntToStr(Sum);
end;

教えて!↑

82 名前:デフォルトの名無しさん mailto:sage [2005/12/16(金) 15:44:01 ]
Integer
0
a
Sum
i

83 名前:デフォルトの名無しさん mailto:sage [2005/12/18(日) 04:51:49 ]
すんません、教えてください。

TPopupMenuに動的にメニューを追加する方法なんですが、サブメニューも追加したくて・・・
例えば

A
 -SubA
 -SubB
B
 -SubA
 -SubB
 -SubC

こんな感じでサブメニュー含めて動的に追加するにはどうしたらいいですかね?

84 名前:デフォルトの名無しさん mailto:sage [2005/12/18(日) 09:33:06 ]
>>83
>>57

85 名前:デフォルトの名無しさん mailto:sage [2005/12/20(火) 06:50:34 ]
>>78-80
function CountAlphaWord(const str:    AnsiString):    Integer;
var
    i:    Integer;
    cnt:    Integer;
    isAlphaNow:    Boolean;
    isAlphaPrev:    Boolean;
begin
    isAlphaPrev:=False;

    cnt:=0;
    i:=1;

    while (i <= Length(str)) do
    begin
        isAlphaNow:=False;

        if ( (str[i] in LeadBytes)) then
        begin
            Inc(i,2);
        end
        else
        begin
            if (str[i] in ['a'..'z', 'A'..'Z']) then
            begin
                isAlphaNow:=True;
            end;
            Inc(i);
        end;


86 名前:デフォルトの名無しさん mailto:sage [2005/12/20(火) 06:54:35 ]
        if (not isAlphaPrev) and isAlphaNow then
        begin
            Inc(cnt);
        end;
        isAlphaPrev:=isAlphaNow;

    end;

    result:=cnt;
end;

//ここまで
よろしくお願いします

87 名前:デフォルトの名無しさん mailto:sage [2005/12/20(火) 14:36:57 ]
>>85-86

100点。

キモは、

if (not isAlphaPrev) and isAlphaNow then

ですね。これでトンネルの入り口を認識しているのだね。Boolean の変数を二つ
つかって、論理が分かりやすくなっています。わたしの実装だと、IsTunnel という
Boolean の変数をひとつだけ使っているので、今回の実装より簡単ですが、コードは
読みにくいです。他人の実装をみると、自分との違いが分かって勉強になります。

さて、次の課題は、多分予想できていると思いますが、トンネルの出口も認識して
数だけでなく、位置と長さも返すような関数を作ってください。

type
TPosLength = record
Position: integer;
Length : integer;
end;

TPosLenArr = array of TPosLength;

function SearchAlphaWord(const str: string; var pl: TPosLenArr): integer;

>>79 の全文をヒントとしてください。

88 名前:デフォルトの名無しさん mailto:sage [2005/12/23(金) 05:34:45 ]
>>87
function SearchAlphaWord(const str: string; var pl: TPosLenArr): integer;
var
    i:    Integer;
    cnt:    Integer;
    isAlphaPrev:    Boolean;
    isAlphaNow :    Boolean;
    iPrev:    Integer;
begin
    isAlphaPrev:=False;

    cnt:=0;
    i:=1;

    while (i <= Length(str)) do
    begin
        isAlphaNow:=False;
        iPrev:=i;

        if ( (str[i] in LeadBytes)) then
        begin
            Inc(i,2);
        end
        else
        begin
            if (str[i] in ['a'..'z', 'A'..'Z']) then
            begin
                isAlphaNow:=True;
            end;
            Inc(i);
        end;

89 名前:デフォルトの名無しさん [2005/12/23(金) 05:35:25 ]
        if (not isAlphaPrev) and isAlphaNow then
        begin
            Inc(cnt);

            if cnt>Length(pl) then
            begin
                SetLength(pl, cnt+10);
            end;
            pl[cnt-1].Position:=iPrev;
        end
        else    if isAlphaPrev and (not isAlphaNow) then
        begin
            pl[cnt-1].Length:=iPrev-pl[cnt-1].Position;
        end;

        isAlphaPrev:=isAlphaNow;
    end;

    SetLength(pl, cnt);
    result:=cnt;
end;
//ここまで
よろしくお願いします

90 名前:デフォルトの名無しさん mailto:sage [2005/12/23(金) 11:51:19 ]
>>88-89

90点。

ヒントの

> トンネルの中にも駅があることを考慮しなければなりません。ですから、名古屋
> は違いますが終点がトンネルの中の場合もありえます。

を忘れています。アルファベットでテキストが終わる場合を考慮してください。

...
isAlphaPrev:=isAlphaNow;
end;

if isAlphaNow then pl[cnt-1].Length:=iPrev+1-pl[cnt-1].Position; // これを追加

SetLength(pl, cnt);
result:=cnt;
end;

あと、一つも見つからない場合もありますので、while の前に

isAlphaNow := false;
iPrev := 1;

で初期化しておくとコンパイラの警告が出ませんね。

文字列操作は列挙や置換、抽出、パースなどいろいろありますが、少々当方も飽きてきた
ので次はリストクラスから出題します。すこし時間をください。



91 名前:デフォルトの名無しさん mailto:sage [2005/12/23(金) 12:10:18 ]
>>88-89

リストクラスはもっとも簡単そうな文字列のリスト TStringList から始めます。
最初はソートの練習です。

procedure TForm1.Button1Click(Sender: TObject);
var
  sl: TStringList;
  i: integer;
begin
  Randomize;
  sl := TStringList.Create;
  try
    for i := 1 to 20 do sl.Add(IntToStr(Random(1000)));
    Memo1.Lines.Assign(sl);
  finally
    sl.Free;
  end;
end;

にすると、0-999 のランダムな数値に対応する文字列が sl に20個保持され、その内容が Memo1 に
表示されます。コードを継ぎ足して、数値の小さい方から(昇順)並べ直して見てください。

TStringList.CustomSort を使います。

92 名前:ささ ◆6KVcpBNXy. [2006/01/26(木) 15:45:51 ]
みなさん。こんにちゎ。経済学部のささと申します。
パスカル(Delphi)の授業での課題がわかりません。。教えてください!
3科目、10人分のデータを入力して各人の合計点と科目毎の平均点を作れ!
という課題が出ました。。。

先生に下記を改変するとやりやすいといわれました。repeatとwhileとforまでしか習っていません。
Score :array[0..1000] of integer; 
begin
writeln('入力得点の平均と偏差値を計算します'); writeln('入力後、負の数を入力すると…終了します。');
kazu :=0;
repeat
write('点数は?'); readln(data);
if data >= 0 then
begin 
kazu := kazu + 1;
score[kazu] := data
end
until data < 0;
goukei := 0;  for i := 1 to kazu do goukei := goukei + score[i];  heikin :=goukei / kazu;
goukei :=0;  for i := 1 to kazu do  goukei := goukei + Sqr(score[i]); hensa := sqrt(goukei /kazu - sqr(heikin));
writeln('点数  偏差値');
for i := 1 to kazu do  writeln(score[i]:4, 50 +10 * (score[i]-heikin)/ hensa:10:1);
writeln(' 平 均 =',heikin:5:1);  writeln('標準偏差=',hensa:5:1);
readln;
end.

93 名前:棄民党党首 ◆8slekwWKD6 [2006/01/26(木) 17:00:39 ]
やひゃひゃひゃ。おまいら。

AssignFile(f, s); Reset(f);

で s にアクセント記号と漢字交じりのファイル名をWideStringでぶちこんでみたら
開かんぞ。

TntのUnicode Componentsをいぢってみたが、AssignFileのUnicode版がみつからん。

でしかたないから
WideRenameFileで名前を'safe.bin'とかに変更しちゃって。
フツ〜にAssignFileで開いて処理してからまた
WideRenameFileで名前をUnicodeの名前へもどしますた。

わたしってなんて天才♪

94 名前:デフォルトの名無しさん mailto:sage [2006/02/10(金) 02:28:56 ]
Delphiってなくなるの?
Turbo Pascal時代からずっと使って来ただけに、
手に馴染んだ開発環境がなくなると困る。

95 名前:デフォルトの名無しさん mailto:sage [2006/02/10(金) 04:04:10 ]
>>94
ボーランドが手放すだけでDelphiがなくなるわけじゃないから安心しる。

96 名前:デフォルトの名無しさん mailto:sage [2006/02/10(金) 08:15:16 ]
買い手が無ければなくなるんじゃね?

97 名前:デフォルトの名無しさん [2006/02/10(金) 14:45:48 ]
で、MDIでWM_COPYDATAを子フォームで受け取るにはどーすんの?


98 名前:デフォルトの名無しさん mailto:sage [2006/02/10(金) 16:58:38 ]
受け取るのは簡単だろ

99 名前:デフォルトの名無しさん [2006/02/10(金) 17:29:53 ]
>>98
え?マジすか?kwsk!
とあるスレッドからMDI子フォームにSendMessageしたいんです。
そのスレッドでは、MDI子フォームのウィンドウハンドルを取得する事は
出来るのですが、SendMessageしてもMDI子フォームにメッセージが来ないです。
もう泣きそうです。
もちろん、MDI子フォームではメッセージを受け取れるようにしているのですけども・・・。


100 名前:デフォルトの名無しさん mailto:sage [2006/02/10(金) 17:49:34 ]
どうやってハンドルをみつけたの?








[ 続きを読む ] / [ 携帯版 ]

次100 最新50 [ このスレをブックマーク! 携帯に送る ] 2chのread.cgiへ
[+板 最近立ったスレ&熱いスレ一覧 : +板 最近立ったスレ/記者別一覧]( ´∀`)<190KB

read.cgi ver5.27 [feat.BBS2 +1.6] / e.0.2 (02/09/03) / eucaly.net products.
担当:undef