2014年10月26日

C#で文字変換表に基く文字列の変換

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その44

■問題 (出題者: mc さん)
UNIXのtrコマンドや、Perlのtr演算子のように、指定した対応づけに従って文字を変換する関数を作成して下さい。
予め言語内に用意されている場合は、(1)一般的な使用法と、(2)より進んだ使用方法を提示して下さい。

'ABCDEF'と'abcdef'等すべて対応する文字を書く必要があるものを、(1)基本版、'A-Z'と'a-z'のように"-"で範囲を指定できるものを(2)拡張版、2を更に発展させたものを(3)発展版とします。任意のものを選んで解答して下さい。
実行例. (与えられた文字列が、"typewriter"の場合)
tr 'qwertyuiop' 'QWERTYUIOP' "typewriter"
=> TYPEWRITER
1
2
3
4
5
6
7
8

;; 基本版/Arc
(def tr (orig subst str)
  (tostring
   (each c str
     (pr (aif (pos c orig) (subst it) c)))))

(tr "qwertyuiop" "QWERTYUIOP" "typewriter")
;=>"TYPEWRITER"



ここでは、基本版だけのコードを書きました。
問題文には、"変換する関数"とありますが、C#らしくここではクラスTranscoderを定義することとしました。

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace Doukaku.Org {
    class Transcoder {
        private Dictionary<char,char> dict = new Dictionary<char,char>();

        public Transcoder(string from, string to) {
            for (int i = 0; i < to.Length; i++ )
               dict.Add(from[i], to[i]);
        }

        public string Execute(string s) {
            StringBuilder sb = new StringBuilder();
            foreach (var c in s) {
                if (dict.ContainsKey(c))
                    sb.Append(dict[c]);
                else
                    sb.Append(c);               
            }
            return sb.ToString();
        }
    }
}

あまりにも普通すぎるコードですが、まあ良しとしましょう。 普通が一番です。
このクラスの使用例は、こんな感じ。

class Program {
    static void Main(string[] args) {
        Transcoder tr = new Transcoder("qwertyuip","QWERTYUIP");
        Console.WriteLine(tr.Execute("typewriter"));
        Console.ReadLine();
    }
}

  

Posted by gushwell at 22:30Comments(0)TrackBack(0)

『C#プログラミングレッスン』のバックナンバー「続 アルゴリズム編」

   このエントリーをはてなブックマークに追加 Clip to Evernote
メールマガジン『C#プログラミングレッスン』のバックナンバー「続 アルゴリズム編」を下記ページからダウンロードできるようにしました。


Gushwell"s C# Programming Page」-「メールマガジン『C#プログラミングレッスン』書庫


  
Posted by gushwell at 13:34Comments(0)TrackBack(0)

2014年10月19日

C#でキッチンタイマー

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その43

一ヶ月ほど空いてしまいましたが、このシリーズ再開します。
WPFの記事に比べると、本当にアクセスが少ないシリーズですが、気にせず進めていきます。(^^;;


■問題 (ところてん さん)
キッチンタイマーを作ってください。 要件は以下のとおりです。
・タイマーが鳴るまでの時間を入力可能
・残り時間を表示
・タイマーが切れたら音がなる

まずは、KitchenTimer の定義。

using System;
using System.Timers;

namespace Doukaku.Org {

    public class KitchenTimer {

        private System.Timers.Timer _timer;
        private TimeSpan _elapsedTime;
        private TimeSpan _target;
        private Action _action;
        private Action _endAction;
        private Object _lockobj = new object();

        public void Start(TimeSpan time, Action action, Action endAction) {
            _elapsedTime = new TimeSpan();
            _target = time;
            _action = action;
            _endAction = endAction;
            _timer = new System.Timers.Timer();
            _timer.Interval = 1000;
            _timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            _timer.Start();
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e) {
            lock (_lockobj) {
                if (_timer == null)
                    return;
                _elapsedTime = _elapsedTime.Add(new TimeSpan(0, 0, 1));
                _action();
                if (_target <= _elapsedTime) {
                    _timer.Stop();
                    _endAction();                  
                }
            }
        }

        public void Stop() {
            lock (_lockobj) {
                _timer.Stop();
                _timer = null;
            };
        }

        public TimeSpan TimeLeft {
            get {
                var left = _target - _elapsedTime;
                if (left.TotalMilliseconds <= 0)
                    return new TimeSpan(0, 0, 0);
                return left;
            }
        }

    }
}

一定間隔毎に引数で受け取ったActionデリゲートがよばれるようにしています。
また、タイマーが終了した時点でも、もう一つのActionデリゲートがよばれます。
こうすることで、前回のバイナリークロック同様、GUIへの依存がないようになっています。

このクラスを使い WindowsFormsアプリを作成します。
タイマーが切れたらブザーが鳴りますが、このブザーは、Stopボタンが押されるまで鳴り続けます。
こまかな説明は省略。

using System;
using System.Media;
using System.Threading;
using System.Windows.Forms;

namespace Doukaku.Org {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private Status status = Status.Stop;
        private int minutes = 0;
        private int seconds = 0;
        private KitchenTimer kt;

        private void buttonStart_Click(object sender, EventArgs e) {
            switch (status) {
            case Status.Stop:
                Start();
                break;
            case Status.Running:
                Stop();
                break;
            case Status.Buzzer:
                Restore();
                break;
            }
        }

        private void buttonReset_Click(object sender, EventArgs e) {
            if (status == Status.Stop) {
                status = Status.Stop;
                buttonStart.Text = "Start";
                numericUpDown1.Value = 0;
                numericUpDown2.Value = 0;
            }
        }

        private void Start() {
            minutes = (int)numericUpDown1.Value;
            seconds = (int)numericUpDown2.Value;
            TimeSpan ts = new TimeSpan(0, minutes, seconds);
            status = Status.Running;
            buttonStart.Text = "Stop";
            kt = new KitchenTimer();
            kt.Start(ts,
                () => {
                    this.Invoke((MethodInvoker)delegate {
                        TimeSpan left = kt.TimeLeft;
                        numericUpDown1.Value = left.Minutes;
                        numericUpDown2.Value = left.Seconds;
                    });
                },

                () => {
                    status = Status.Buzzer;
                    while (status == Status.Buzzer) {
                        SystemSounds.Asterisk.Play();
                        Thread.Sleep(200);
                    }
                }
            );
        }

        private void Stop() {
            kt.Stop();
            Restore();
        }

        private void Restore() {
            status = Status.Stop;
            buttonStart.Text = "Start";
            numericUpDown1.Value = minutes;
            numericUpDown2.Value = seconds;
        }

        enum Status {
            Stop,
            Running,
            Buzzer,

        }
    }
}
  
Posted by gushwell at 22:30Comments(0)TrackBack(0)