黙々とC#

"In a mad world of VBA, only the mad are sane" 『VBAという名の狂った世界で狂っているというのなら私の気は確かだ』

検索

本記事は、Excel C# Script入門講座の1記事です。

検索

シート内で文字列を検索するは、検索したい範囲を表すRangeオブジェクトを用意し、RangeオブジェクトのFindメソッドを使用します。引数で、検索条件を指定します。

Findメソッドの構文

(Rangeオブジェクト).Find(What, After, LookIn, LookAt, SearchOrder, SearchDirection, MatchCase, MatchByte, SearchFormat)

Findメソッドの戻り値

検索範囲の先頭のセルを表す Rangeオブジェクトが戻ってきます。

一致するデータが見つからなかった場合、null が戻ってきます。

Findメソッドの引数

引数名 必須 / オプション 内容
What 必須 検索するデータです。文字列など、セル内のデータに該当する値を指定します。
After 省略可能 検索を開始する1つ前のセルを指定します。
LookIn 省略可能 検索対象を指定します。
LookAt 省略可能 「セル内容が完全に同一のものだけを検索するか」どうかを指定します。
SearchOrder 省略可能 検索の際、行列のいずれの方向(順序)に検索するかを指定します。
SearchDirection 省略可能 検索を前方向、後ろ方向のどちら向きに検索するかを指定します。
MatchCase 省略可能 大文字と小文字を区別するには、true を指定します。既定値は false です。
MatchByte 省略可能 半角、全角を区別するには、trueを指定します。既定値は false です。
SearchFormat 省略可能 検索において、書式条件を検索対象とするかを指定します。規定値はfalseです。
引数After

引数 After には、セル範囲内(Rangeオブジェクト内)の1つのセルを指定する必要があります。

これは、ユーザーが通常の画面上で検索を実行する際のアクティブなセルの場所に対応しています。このセルの次のセルから検索が開始され、範囲内の他のセルがすべて検索されたあとに、指定されたセルが検索されます。

この引数を省略すると、対象セル範囲(Rangeオブジェクトの範囲)における左上端のセルが検索の開始点になります。

引数LookIn

引数 LookIn には、XlFindLookIn 列挙型を指定します。各メンバの意味は以下のとおり。

名前 説明
xlComments -4144 コメント
xlFormulas -4123 数式
xlValues -4163
引数LookAt

使用できる定数は、XlLookAt 列挙型の xlWhole または xlPart です。

名前 説明
xlWhole 1 検索文字列全体に一致する(完全に一致する)候補のみを取得します。
xlPart 2 検索文字列の一部に一致する候補を取得します。
引数SearchOrder

使用できる定数は、XlSearchOrder 列挙型の xlByRows または xlByColumns です。

名前 説明
xlByRows 1 行を横方向に検索し終えた後、次の行を検索します。
xlByColumns 2 行を下方向に検索し終えた後、次の列を検索します。
引数SearchDirection

使用できる定数は、XlSearchDirection列挙型の xlNextまたはxlPreviousです。

名前 説明
xlNext 1 後方検索(通常の検索方向)
xlPrevious 2 前方検索
引数MatchByte

「半角と全角を区別する」場合にtrueを指定にします。半角・全角の区別を行わない場合にはfalseを指定します。

この引数は、OSに 2 バイト (全角) 文字の言語サポートが導入されている場合にだけ使用できます。

引数SearchFormat

検索において書式条件を有効する(文字だけでなく書式も含めて検索する)場合にtrueにします。デフォルトはfalseです。

書式条件は、ApplicationオブジェクトのFindFormatプロパティで設定します。

サンプルコード

下記の例では、"Sheet1"に文字列"りんご"が存在するか検索し、存在した場合その位置を表示します。

var keyword = "りんご";
var hitRange = Excel.Worksheets("Sheet1").Cells.Find(keyword);
var message = "";
if (hitRange == null)
{
    message = $"{keyword} は見つかりませんでした";
}
else
{
    var r = hitRange.Row;
    var c = hitRange.Column;
    message = $"{keyword} は {r}行目{c}列目にあります";
}
Excel.StatusBar = message;

下記例では、"Sheet1"に文字列"C#"と完全一致するセルが存在するか検索し、存在した場合そのセルを太字にします。

var keyword = "C#";
var hitRange = Excel.Worksheets("Sheet1").Cells.Find(What:keyword, LookIn:-4163, LookAt:1);
if (hitRange != null)
{
    hitRange.Font.Bold = true;
}

try ~ catch

本記事は、Excel C# Script入門講座の1記事です。

try ~ catch

スクリプト内でエラーが発生した場合のプログラムの制御には、try ~ catch ステートメントを使用します。

try ~ catch ステートメントは、try ブロックと、それに続く 1 つ以上の catch 句で構成されます。catch句には例外処理を記載します。これにより、 例外が起こったときでもプログラムが異常な動作をしない堅牢なスクリプトを作ることが可能となります。

例えば以下のように使います。

object o2 = null;
try
{
    int i2 = (int)o2;   //例外の発生
}
catch (NullReferenceException e)  //発生する例外に合わせた例外クラスの指定
{
    //エラー処理
}

エラーには、大きく分けて実行時エラーと構文エラー(コンパイルエラー)とがあります。

実行時エラーとはシステムで処理できない動作を実行しようとした場合に発生するエラーです。C#(C# Script)では、実行時にエラーが発生すると、例外がスローされます。

構文エラーとは文法上の規則に違反した場合に発生するエラーで、プログラム実行前のコンパイル時に発生します。C# Scriptでは、構文エラーに関しては、実行前にエラーが表示されます。

tryブロックには、実行時エラーが発生する(例外がスローされる)可能性のあるコードを含ませます。このブロックは、例外がスローされるか、ブロックが正常に終了するまで実行されます。

catch 句は、引数なしで使用してすべての種類の例外をキャッチすることが可能ですが、そのようなコードは推奨されません。通常は、回復方法(例外が発生した場合の処理方法)が分かっている例外のみキャッチします。

try ~ finally

tryブロックでエラーが発生した場合でも、確実に実行したい処理がある場合には、finallyブロックを使用することができます。

finallyブロックは、たとえばtryブロック内で確保したリソースを確実に開放したい場合に利用することができます。

try
{
  //例外が投げられる可能性のあるコード
}
finally
{
  //例外発生の有無にかかわらず実行したいコード
  //リソースの開放などを行う
}

goto

本記事は、Excel C# Script入門講座の1記事です。

goto

無条件に処理を分岐させたい場合には、goto ステートメントを使用することができます。ただし、gotoステートメントを多用するとプログラムが分かりにくくなるので積極的には使わない方が良いでしょう。

例えば以下のように使います。

LABEL: // ジャンプ先を示すラベル
var x = 1;
goto LABEL;

//※このサンプルコードは無限ループします

goto ステートメントの使いドコロの1つとしては、階層の深い入れ子のループから抜ける際に使います。

for(var i = 1; i < 100; i++)
{
    for(var j = 1; j < 100; j++)
    {
          if( i > 50 && i == j )
          {
                goto EXITLOOP;
          }
    }
}

EXITLOOP:

goto case

また、goto は switch ステートメントの特定の switch-case ラベルまたは default ラベルに制御を移動するのに使用することができます。

var n = Excel.ActiveWorkbook.ActiveSheet.Range("A1").Value;
var cost = 0;
switch (n)
{
    case 1:
        cost += 25;
        break;
    case 2:
        cost += 25;
        goto case 1;
    case 3:
        cost += 50;
        goto case 1;
    default:
        break;
}

Excel.ActiveWorkbook.ActiveSheet.Range("A2").Value = cost;

return, break

本記事は、Excel C# Script入門講座の1記事です。

return, break

return

C# スクリプトの処理を途中で抜ける場合、returnステートメントを使用します。

var x = 1;
return;    //ここでスクリプト終了

var y = 2; //この処理は実行されない。

なお、メソッド内でreturnを使用した場合は、通常のC#と同様、当該メソッドを抜けるのみです。

break

whileステートメントやforステートメントを処理途中で抜けるには、breakステートメントを使用します。

for(var i = 1; i < 100 ; i++)
{
    if( i = 10) { break; }
}

using

本記事は、Excel C# Script入門講座の1記事です。

using

usingステートメントは、IDisposableインターフェースを実装したオブジェクトを呼び出した際に、確実にDispposeメソッドが呼ばれるように保証するための簡易構文です。

#r "System.Drawing"
using System.Drawing;

using (var font1 = new Font("Arial", 10.0f)) 
{
    var charset = font1.GdiCharSet;
}

上記例のFontオブジェクトのように、アンマネージ リソース (この場合はデバイス コンテキスト) にアクセスするマネージ型の例です。アンマネージ リソースや、それをカプセル化するクラス ライブラリ型は他にもたくさんあります。そのような型はすべて、IDisposable インターフェイスを実装する必要があります。

一般に、IDisposable オブジェクトを使用するときは、それを using ステートメントで宣言して、インスタンス化する必要があります。 using ステートメントは、ステートメントブロックを抜けると必ず Dispose メソッドを呼び出します。 Disposeメソッド が呼び出されるとすぐに、オブジェクト自体がスコープの外側に出されます。 オブジェクトは、using ブロック内では読み取り専用です。変更したり再割り当てしたりすることはできません。

using ステートメントを使うと、オブジェクトでのメソッドの呼び出し中に例外が発生した場合でも Dispose が必ず呼び出されます。 usingステートメントは、オブジェクトを try ブロックに配置し、finally ブロックで Dispose を呼び出すコードと等価です。

while

本記事は、Excel C# Script入門講座の1記事です。

while

条件により処理を繰り返したい場合、whileステートメントを使用します。

while は"while (条件式)"の形式で条件を指定します。条件式がtrueの間、処理が実行されます。 従って、通常は処理の中でwhile文の条件式がfalseになるようにしたり、 繰り返しを中断するような文を記述します。そうでないとwhile文は処理を永遠にし続けてしまうからです。

"while ( 条件式 )"は、2通りの記述方法があります。記述方法により処理内容が異なってきます。

while 文

以下のように、whileの位置を前にした場合、条件式を満たしているのかを判断してから 繰り返す処理を実行します。

while ( 条件式 )
{
  //繰り返す処理
}

なお、C# (C# Script)にuntilは存在しません。論理演算子 ! を用いて条件を否定の形にして下さい。

下記の例では、まず初期値として変数 i に 1 が代入しておき、次に i が11以下かどうかを評価し、セルに値を代入し、次に i の値を1つ加算し、 もう一度 i が11以下かどうかを評価し、セルに値を代入します。この処理を i が10以上になるまで繰り返します。

var i = 1;
while ( i < 11 )
{
  Excel.Worksheets("Sheet1").Cells(i, 1).Value = i;
  i++;
}

do while文

上記記述方法に対してwhileの位置を後ろにした場合、繰り返す処理を実行してから 条件式を満たしているか判断します。つまりどのような条件でも1回は繰り返す処理 を実行します。

do
{
  //繰り返す処理
}
while(条件式);

なお、この記述方法を用いる場合、while(条件式)の末尾に ; (セミコロン)が必要です。

下記の例では、まず初期値として変数 i に 10 が代入しておき、セルに値を代入し、次に i の値を1つ加算し、 i が11以下かどうかを評価します。つまりWhile 条件式を評価する前に処理を 1回実行しています。i の値は11なので 繰り返す処理を実行せずに終了します。

var i = 10;
do
{
  Excel.Worksheets("Sheet1").Cells(i, 1).Value = i;
  i++;
}
while(i < 11);

for

本記事は、Excel C# Script入門講座の1記事です。

for

条件により同じ処理を繰り返したい場合(反復処理を行いたい場合)には、forステートメントが利用できます。

for(初期化式; 条件式; 更新式)
{
  //反復処理
}

下記の例では、まず変数iに1が代入され(「初期化式」)、次にiが10以上かどうかを評価し(「条件式」)、セルに値を代入し(「反復処理」)、次にiの値を1つ加算し(「更新式」)、再度、iが10以上かどうか評価し(「条件式」)、セルに値を代入し(「反復処理」)、…という処理を繰り返します。この処理は、iが10以上になるまで繰り返されます。

for(var i = 1; i <= 10; i++)
{
    Excel.Worksheets("Sheet1").Cells(i, 1).Value = i.ToString();
}

上記例からも分かるように、初期化式は、for文で反復処理に入る前に1度だけ実行されます。