English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
MQL5 プログラミング基礎:文字列

MQL5 プログラミング基礎:文字列

MetaTrader 5 | 27 11月 2015, 09:01
6 020 0
Dmitry Fedoseev
Dmitry Fedoseev

はじめに

文字列、あるいは文字列変数は文字データ、すなわちテキストを格納するのに使用されます。

string str="Any text";

MQL5 言語は文字列と連携するために使いやすい機能性を幅広く提供します。実際には、EAおよびインディケータをプログラムする際、情報メッセージを作成するためには主に文字列が使用されます。インディケータにおいては、文字列は特定条件(たとえばトレードシグナル)を満たす点でメッセージです。一方Expert Advisors では文字列は売買活動の結果を報告することがあります。実行の際、Expert Advisor、スクリプト、インディケータはユーザーが設定するパラメータをチェックし、設定されたパラメータが無効の場合は通知をプリントします。通知のほか、パラメータ設定に関する推奨事項を提供するメッセージを作成しているのを見かけることがあります。広い意味で、MQL5でプログラムするとき、文字列は何にもまして使い勝手の良さを提供してくれます。

その上文字列はファイルと連携するとき欠かせないものです。ファイルへのデータ書き込みやファイルからの読み出しは文字列変数を使って行われます。明らかにファイルと連携する別の方法を選択することもできます。数値変数と配列を読んだり書いたりするバイナリ法です。ただし、データ量があまり大きくなければ、テキストファイルと文字列を使用する方が好都合です。この場合、プログラム処理はユーザーにとって判りやすく、プログラム開発手順はよりシンプルで、データ管理が直接できるようになっています。テキストファイルデータはプログラム内部のデータと見た目が変わりません。

文字列の使用は、前もって必要なパラメータ数が判らない場合(たとえばビルドアップを平均化するロットサイズ)のデータ(パラメータ)入力に関するプログラム特性の幅を大きく広げます。そのような場合には、値はセミコロンのような分離記号によって区切られた1行の文字列に書かれます。

input string Lots="0.1; 0.2; 0.3; 0.5";

そして Expert Advisor を初期化するとき、文字列は分割され、数値配列が書き込まれます。残念ながら最適化でそのような文字列パラメータを詳細に調べること、すなわち段階値に従って初期値および終了値を設定することは不可能です。おそらくプロパティウィンドウで多数の数値を使用する方が好ましい場合もあることでしょう。実質的には数に制限はないので、利便性の問題と意義(最適化の機能は必要かどうか)ということになります。

たぶんパラメータの最適化が要件ではないとされる場合もあるでしょう。たとえば、通知機能を無効にする場合です。MQL5 は多様なユーザー通知法をサポートしています。それらは、音声通知、ポップアップ通知、Eメール通知、プッシュ通知です。プロパティウィンドウ内でこれら通知それぞれに対してブールタイプのスイッチを作成する(最低4つの変数が必要です)ことができます。または、変数の数を減らして1つの文字列変数にすることも可能です。

音声通知を有効にする必要があれば "s" (音声)を書きます。またEメール通知も必要であれば、"e" を追加します。変数を一つ使うだけでどんな通知の組合せも有効にすることが可能です。Expert Advisorについては外部プラメータ数はほとんど重要ではありません。ただ使い勝手の問題です。

一方、インディケータを作成する場合、外部パラメータ数を減らす努力をする必要があります。インディケータはパラメータ数に制限のある関数iCustom() または IndicatorCreate()を使って Expert Advisorまたは別のインディケータから呼ばれます(iCustom() だけでパラメータ64、 IndicatorCreate() 関数のパラメータ配列サイズは64エレメント)。よって文字列の使用は大きな実用的価値があるのです。

本稿は文字列に関わる標準 MQL5 関数をすべて再考し、いくつか便利なカスタム関数を作成します。

 

文字列変数の宣言

その他のあらゆる変数タイプ同様、文字列変数は宣言可能です。

string str;
または宣言(ある値に対して初期化される)の際、値を割り当てることができます。
string str="Any text";

文字列の長さに制約はありません。長い文字列は便宜上複数の従属文字列に分割されます。

string str= "A long string can be "
            "split into several "
            "substrings";
//--- output the results
Alert(str);

この方法で初期化されるとき、str 変数は『長い文字列は複数の従属文字列に分割される可能性があります』を含む文字列を持つことになります。

ここで少し飛躍すると、パラメータなしで宣言される文字列変数の値は空の文字列とは同じではないということに注意が必要です。

string str="";

みなさんはご自身で確認することができます。

string str1;
string str2="";
//--- output the comparison results
Alert(str1==str2);

このコードを実行すると、『偽』を 警告 するウィンドウがポップアップします。初期化されていない文字列変数は、空の文字列 ""とは異なる NULL 値を持ちます。そのことを忘れないようにする必要があります!文字列を使用するときには、文字列が空かどうかひじょうに頻繁に確認する必要があります。空の文字列 "" も含めすべての文字列を初期化するというルールに忠実に従うか、あるいは "" とも NULL とも違うか確認する必要があります。

if(str!="" && str!=NULL)
  {
   //--- some operation with a string
  }

最初の方法は確認条件をシンプルにするのでよりお薦めです。 

変数サイズを確認するときも同じように行うことができます。サイズを決定するには StringLen() 関数を使用します。

if(StringLen(str)!=0)
  { 
   //--- some operation with a string
  }


文字列の連結

文字列を使用するときに行う主要な、もっとも一般的な処理は文字列同士を連結することです。すなわち、語を使ってフレーズを構築するのです。連結は記号 "+" を使って実行されます。

string str1,str2,str3,str4,str5;
//--- assign values
str1="Programming";
str2="in MQL5";
str3="for MetaTrader 5";
//--- add up the strings
str4=str1+" "+str2;
str5=str1+" "+str3;
//--- output the results
Alert(str4);
Alert(str5);

このコードの実行後、str4 変数は『MQL5でのプログラミング』となります。また str5 変数は『MetaTrader 5のためのプログラミング』となります。上記例は2つの文字列の連結方法を示します。結果の文字列は別の変数に割り当てられています。

もう一つの文字列はメインの文字列に連結されることがひじょうによくあります。 

string str1,str2,str3;
//--- assign values
str1="Programming";
str2="in MQL5";
str3="for MetaTrader 5";
//--- add up the strings to the main string
str1=str1+" "+str2;
str1=str1+" "+str3;
//--- output the results
Alert(str1);

このコードの実行後、str1 文字列は『MQL5でのMetaTrader 5用プログラミング』となります。上記例は文字列をメインの str1文字列に連結する方法を示しています。結果は後者文字列に割り当てられています。同じ処理をもっとシンプルな方法で書くことができます。

str1+=str2;
str1+=str3;
または
str1+=str2+str3;

"=" の左にある記号 "+" は "=" の右の式が str1 変数に加えられていることを意味します。

また文字列をメイン文字列の冒頭に追加することも可能です。これは最後から二番目の例のように実装されます。メインの文字列は追加文字列に加えられ、結果の文字列はメイン変数に割り当てられます。

string str1,str2,str3;
//--- assign values
str1="Programming";
str2="in MQL5";
str3="for MetaTrader 5";
//--- concatenate strings, with a string being added to the beginning
str3=str2+" "+str3;
str3=str1+" "+str3;
//--- output the results
Alert(str3);

次のフレーズ『MQL5でのMetaTrader 5用プログラミング』は今では str3 変数にあります。同じものを1行の文字列を使用して実装することが可能です。 

str3=str1+" "+str2+" "+str3;
","(コンマ)を使って連結することができる場合もあります。関数 Alert()、Print()、Comment() を呼ぶときこれが可能です。
Print(str1," ",str2," ",str3);

この場合、最後の結果は記号 "+" を使うのと同じです。

Print(str1+" "+str2+" "+str3);

記号 "," は実は文字列を連結しません。コンマはすべての関数内ではパラメータの分離記号です。関数 Alert()Print()Comment() に対してもしかりです。これら関数は1つの必須パラメータと数多くのオプションパラメータを持ちます。パラメータは事実上、連結される関数に渡されます。パラメータの最大数は 64です。

FileWrite() 関数を用いてファイルに文字列を書く場合も似ています。ただ、FILE_CSV モード(フィールド分離記号を伴い)でファイルを開く場合、コンマはファイルを開くときに指定する分離記号文字と置き換えられます(分離子が指定されていなければ、デフォルトではタブが使用されます)。分離記号を指定せず FILE_TXT モードでファイルを開くとき、記号 "+" を使った結果は "," を使った結果と同じになります。

//--- write to the first file
int h=FileOpen("1.txt",FILE_WRITE|FILE_ANSI|FILE_CSV);
FileWrite(h,"1","2","3");
FileClose(h);
//--- write to the second file
h=FileOpen("2.txt",FILE_WRITE|FILE_ANSI|FILE_CSV);
FileWrite(h,"1"+"2"+"3");
FileClose(h);
//--- write to the third file
h=FileOpen("3.txt",FILE_WRITE|FILE_ANSI|FILE_TXT);
FileWrite(h,"1","2","3");
FileClose(h);
//--- write to the fourth file
h=FileOpen("4.txt",FILE_WRITE|FILE_ANSI|FILE_TXT);
FileWrite(h,"1"+"2"+"3");
FileClose(h);

このコード実行後、1.txt ファイルは "1    2    3"を持ちます。また、2.txt ファイルは "123" を持ちます(ファイルは FILE_CSV モードで開いています)。3.txt および 4.txt は同じ内容"123" ( FILE_TXT モードで開かれた)を持ちます。本稿はファイル処理は取り上げません。最後の例に関して不明瞭な部分があっても気にしないでください。それが本稿でこれから述べる内容に影響を与えることはありません。ただ "+" と "," を使用することで文字列追加に関して常に同じ効果をもたらすとは限らないことに留意ください。

記号 "+" 以外に、MQL5 は文字列追加に対して特殊な関数を備えています。それは関数 StringAdd() および StringConcatenate()です。MQL5 参照資料にある関数についての内容によると、それらにより省スペース(使われているワーキングメモリに関し)、迅速に文字列を合計することができます。StringAdd() 関数はある文字列を別の文字列に追加することを可能にします。

string str1,str2,str3;
//--- assign values
str1="Programming";
str2="in MQL5";
str3="for MetaTrader 5";
//--- call the function to concatenate strings
StringAdd(str1," ");
StringAdd(str1,str2);
StringAdd(str1," ");
StringAdd(str1,str3);
//--- output the results
Alert(str1);

このコードの実行後、str1 変数は『MQL5でのMetaTrader 5用プログラミング』を含む文字列を持ちます。

StringConcatenate() 関数を使うと複数の文字列を同時に連結することができます。関数に渡される最初のパラメータは後にリストアップされた文字列の追加先の文字列変数です。渡すことのできるパラメータの最大数は 64です。

string str1,str2,str3;
//--- assign values
str1="Programming";
str2="in MQL5";

str3="for MetaTrader 5";
//--- call the function for combining several strings
StringConcatenate(str1,str1," ",str2," ",str3);
//--- output the results
Alert(str1);

このコードの実行後、str1 変数もまた『MQL5でのMetaTrader 5用プログラミング』を含む文字列を持つこととなります。

 

多様な変数の文字列への変換

メッセージ文字列を作成する際、数値を追加する必要がひじょうによくあります。整数変数(char、uchar、bool、 short、ushort、int、uint、color、long、ulong、datetime)の値を文字列に変換するには IntegerToString() 関数を使用します。

int x=1;
string str="x = "+IntegerToString(x);

ブールタイプ変数を変換するとき、返される文字列は "0" (偽)または "1" (真)となります。同様に color タイプまたは datetime タイプの変数を変換する場合、返される文字列は色あるいは日付(たとえば clrYellow の黄色に対しては"65535"、または日付 2012.01.01 00:00に対しては "1325376000" )という数値表現となります。

real 変数(ダブル、浮動小数点)を文字列に変換するには、DoubleToString() 関数を使用します。この関数の二番目のパラメータは精度(小数点以下の桁数)を判断します。

double x=1.23456;
string str1="x = "+DoubleToString(x,2);
string str2="x = "+DoubleToString(x,3);

このコードの実行後、str1 変数は文字列 "1.23"を、str2 変数は文字列"1.235"となります。指定した桁数への切り捨ては数学的四捨五入のルールに従います。

TimeToString() 関数は日時を標準的フォーマットの文字列(人間が読んで理解する)に変換するのに使用されます。

datetime tm=TimeCurrent(); // Current time 
string str1=IntegerToString(tm);
string str2=TimeToString(tm);

このコードの実行後、str1 変数は時刻の数値表現を伴う文字列(1970年1月1日から経過した秒数)となり、またstr2 変数はフォーマットされた時刻、たとえば"2012.11.02 22:00" (年、月、日、時、分)となります。

TimeToString() 関数を呼ぶとき、日時フォーマットを指定するオプションがあります。選択可能なオプションは以下です。

string str1="Date and time with minutes: "+TimeToString(tm);
string str2="Date only: "+TimeToString(tm,TIME_DATE);
string str3="Time with minutes only: "+TimeToString(tm,TIME_MINUTES);
string str4="Time with seconds only: "+TimeToString(tm,TIME_SECONDS);
string str5="Date and time with seconds: "+TimeToString(tm,TIME_DATE|TIME_SECONDS);

MQL5 はオプションのドロップダウンリストとしてプログラムのプロパティウィンドウに表示される列挙 を作成するひじょうに便利な機能を備えています。そのような変数の値は EnumToString() 関数を使用して文字列への変換も可能です。以下はこの関数処理を示す文字列コードです。

//+------------------------------------------------------------------+
//| Create an enumeration                                            |
//+------------------------------------------------------------------+
enum EMode
  {
   OFF=0,
   Mode1 = 1,
   Mode2 = 2,
   Mode3 = 3 
  };
//+------------------------------------------------------------------+
//| Start the script                                                 |
//+------------------------------------------------------------------+
void OnStart()
  {
   EMode Value=1;
   //--- join strings together
   string str="The "+IntegerToString(Value)+ value" corresponds to "+EnumToString(Value)+ entry" of the Emode enumeration";
   //--- output the results
   Alert(str);
  } 
色の変数を変換することができるようにする類似の機能もあります。ColorToString() 関数を使用することで色の値を色に変換することができます。
color ColorValue=clrRed;
string str=ColorToString(ColorValue,true);

このコードの実行後、str 変数は "clrRed"を持つ文字列を格納します。二番目のパラメータが記述されれば、この関数は RGB コンポーネント(赤、グリーン、ブルー)の値を持つ文字列を返します。

color ColorValue=clrRed;
string str=ColorToString(ColorValue,false);

この場合、str 変数に格納される文字列は "255,0,0"となります。扱う色が標準的な色でない(ウェブカラーパレットに定義されていない、またそのため色名がない)場合、 二番目のパラメータ値にかかわらずコンポーネント値を持つ文字列を返すのに ColorToString() 関数を使用することができます。

型キャストによって変数を変換するもうひとつ別の方法もあります。

int x=123;
string str=(string)x;

この方法でブールタイプの変数を変換するとき、文字列値は『真』あるいは『偽』です。 

bool x=true;
string str=(string)x;

ダブルタイプまたは浮動小数点タイプの変数はできる限り正確に変換されるべきです。それで端数部分のゼロのみ切り捨てることができます。 

double x1=0.1;
double x2=0.123string str1=(string)x1;
string str2=(string)x2;

このコードの実行後、str1 変数は文字列の値"0.1"を格納し、str2 変数は文字列の値"0.123"を持ちます。

 

特殊文字の出力

文字列変数を値に初期化する際、割当て可能な文字列はダブルクオーテーションマークで書き、コンパイラがプログラムコードと文字列を区別できるようにします。文字列内にクオーテーションマークを書き込めるようにするには、マークは通常(文字列をコードから区別する文字として)ここでは使用されず文字列の一部として使用されるということを指定する必要があります。これを実装するには、クオーテーションマークの直前にバックスラッシュ "\" を入れます。

string str1="Simple text";
string str2="\"Text in quotes\"";
//--- output the results
Alert(str1);
Alert(str2);

バックスラッシュもまた特殊文字とみなされるため、文字列内にバックスラッシュが表記されるよう実装するためにはその前にもう一つ別のバックスラッシュを入れる必要があります。

string str="\\";
Alert(str);

このコードの実行後、文字列が持つ唯一の文字は "\" です。

文字列はまた "\t" と表される水平タブ文字を持つこともできます。

string str="Column-1\tColumn-2\tColumn-3";
Alert(str);

この場合、str 変数は文字列"Column-1        Column-2        Column-3"を持ちます。

テキストは "\n"を使って複数行に分ける改行を伴ってプリントすることも可能です。

string str="Line-1\nLine-2\nLine-3";
Alert(str);

ここで、Alert() 関数を実行する結果として、3行のテキストを取得します。

関数 Alert() および MessageBox() を用いてプリントするとき、ファイルに書き込むとき同様、"\t" と "\n"のどちらも使用することができます。ただし、チャートコメント(Comment()関数)にプリントする場合は、ラッピング文字として "\n" のみ適用され、タブ文字 "\t" は無視されます。Print() 関数を用いて出力が行われるときには、前のように"\n" が採用され(文字列の各部がジャーナルの個別行に出力されます)、"\t"は Print() 関数を用いてすべてのメッセージのアウトプットを格納するログファイル内のようにスペースと置き換えられます。

 

パターンに基づく文字列のフォーマット

出力するために文字列をフォーマットする際、そこに複数の数値変数の値をインクルードする必要があります。これは文字列を合計し、数値を文字列に変換することで行われます。ただし、メッセージを構築するコードの文字列が長すぎ、理解しにくく、編集が困難な場合、プログラムの変更が必要となります。

//--- initialize the variables
int Variable1=1;
int Variable2=2;
int Variable3=3;
//--- long addition of strings
string str="Variable1 = "+IntegerToString(Variable1)+", Variable2 = "+IntegerToString(Variable2)+", Variable3 = "+IntegerToString(Variable2);
//--- output the results
Alert(str);

StringFormat() 関数を使用することで同じタスクをもっと簡単に行うことができます。この関数に渡される最初のパラメータは、変数挿入箇所と出力フォーマットの設定の指示を伴うメッセージテンプレートです。それに続くのは、テンプレートに表示される順番ですべての変数を列挙することです。 

//--- initialize the variables
int Variable1=1;
int Variable2=2;
int Variable3=3;
//--- simpler addition of strings
string str=StringFormat("Variable1 = %i, Variable2 = %i, Variable3 = %i",Variable1,Variable2,Variable3);
//--- output the results
Alert(str);

変数を挿入する箇所はT "i"が続く "%" でマークされます。それは上記例では変数は整数として出力されると表記されているものです。むしろ、"i" は文字型整数変数(char, short, int, color)を表します。また "u" は符号なしの整数変数(uchar, bool, ushort, uint)を表します。データタイプ long、ulong、datetime の変数に対しては、付加的にタイプの前に "I64" を入れて変数サイズを指定します。

string LongMin=StringFormat("%I64i",LONG_MIN);
string LongMax=StringFormat("%I64i",LONG_MAX);
string ULongMax=StringFormat("%I64u",ULONG_MAX);
string DateTimeMax=StringFormat("%I64u",DateMax);
//--- output the results
Alert("LongMin = "+LongMin);
Alert("LongMax = "+LongMax);
Alert("ULongMax = "+ULongMax);
Alert("DateTimeMax = "+DateTimeMax);
このコードの結果、変数値を伴うポップアップウィンドウが表示されます。

実数のフォーマットは "f" で表記されます。
double Percents=5.5;
//--- real number as a string
string str=StringFormat("Percents = %f",Percents);
//--- output the results
Alert(str);

このコードの実行後、str 変数は次の文字列を格納します。:"パーセント = 5.500000"デフォルトの出力精度は小数点以下6桁です。また必要な小数点以下の桁数を設定することができます。

string str=StringFormat("Percents = %.2f",Percents);

このため、少数点記号を示す点を入れ、そのすぐ後に小数点以下の桁数が続きます。上記例では2です。この場合、str 変数には以下の文字列が入ります。: 『パーセント = 5.50』このフォーマットオプションは DoubleToString() 関数と完全に同じです。

"0" と "%" に続けて右手に数字の長さを決める数を書くことで数字の全長を指定し、(必要であれば)小数点以下の桁数を指定することができます。

string str=StringFormat("Percents = %06.2f",Percents);

ここでは合計6桁を持ち、そのうちの1つは小数点として使用され、もう2つは小数点以下2桁を表します。よって str 変数に格納される文字列は "Percents = 005.50"です。

メッセージ中にパーセント記号 "%" を表示する必要があれば、連続して "%%"のように2つ書きます。うち一つは値を挿入する場所を指示するのに使用されるからです。

string str=StringFormat("Percents = %06.2f%%",Percents);

この場合 str 変数には 『パーセント = 005.50%』が入ります。

また、整数変数を出力するときは数字の長さを決めることもできます。

int Variable=123;
//--- integer as a string with a set output length
string str=StringFormat("Variable = %05i",Variable);
//--- output the results
Alert(str);

このコードの実行後、str 変数は次の文字列を格納します。:『変数 = 00123』

指定の桁数が数字の桁数よりも小さくても、アウトプットは正確に行われます。

string str=StringFormat("Variable = %02i",Variable); 

ここで str 変数には次のような文字列が入ります。:『変数 = 123』。すなわち指定の長さが2桁であってもアウトプットの数字は3桁です。

実数は、文字 "e" を使う科学的記数法(小数点以下6桁と指数の仮数) を使って出力することができます。

double Variable=123.456;
//--- real number as a string in scientific notation
string str=StringFormat("Variable = %e",Variable);
//--- output the results
Alert(str);

このコードの実行後、str 変数には "1.234560e+002"が入ります。また、小文字 "e"と似た効果を持つ大文字 "E" を使用することも可能です。フォーマットされた文字列では大文字 "E" は小文字 "e" と置き換わります。

実数をフォーマットする方法はまだ他にもあります。6桁(小数点は除外して)のみアウトプット可能な "g" を用いる方法です。数字の整数部分の長さが6桁を超えると、その数字は科学的記数法を使って出力されます。

double Variable1=12.3456789;
double Variable2=1234567.89;
//--- get real numbers as strings using "g"
string str1=StringFormat("Variable = %g",Variable1);
string str2=StringFormat("Variable = %g",Variable2);
//--- output the results
Alert(str1+" "+str2);

上記例ではstr1 変数には "12.3457" が、str2 変数には "1.23457e+006"がきます。変わりに大文字 "G" を使っても効果は同じです。唯一アウトプットで異なる点は小文字 "g" が大文字 "G"に置き換わることです。

StringFormat() 関数により数字表示フォーマットを変換することができます。すなわち、十進法の数字を8進数や16進数に変換することができるのです。数字を8進数に変換するには、文字 "o" を使用する必要があります。

int Variable=17;
//--- real number as a string in the octal system
string str=StringFormat("Variable = %o",Variable);
//--- output the results
Alert(str);

このコードの実行に続いては、str 変数は次の文字列を格納します。:『変数 = 21』(8*2+1=17)

16進数に変換するには"x" または "X" を使います。そのような場合、小文字 "x"を使うと16進数の数字は小文字で構成され、大文字 "X" を使うと16進数の数字は大文字で構成されます。

color Variable=clrBlue;
//--- real number as a string in the hexadecimal system
string str=StringFormat("Variable = %x",Variable);
//--- output the results
Alert(str);

このコードの実行後、str 変数には 『変数 = ff0000』が入ります。

同様に、文字 "d"を使うことで16進数の数字を10進数に戻すことが可能です。

int Variable=0x0000ff;
//--- real number as a string in the decimal system
string str=StringFormat("Variable = %d",Variable);
//--- output the results
Alert(str);

このコードの実行後、str 変数は次の文字列を格納します。:『変数 = 255』

文字 "s" は文字列変数を出力するのに使用することができます。

string Variable="text";
//--- output the string variable
string str=StringFormat("Variable = %s",Variable);
//--- output the results
Alert(str);

このコードを実行するとすぐに、 str 変数に文字列『変数 = text』が格納されます。

負の数が記号 "-" のために移動するとすると、列に数字を出力するとき位置調整が必要になる場合もあります。正の数を負の数と一緒に並べる場合、文字列の最初、"%"の直後にスペースを追加します。この場合、負の数は初めにスペースのある正の数と異なりスペースなしでアウトプットされます。

int Variable1=1;
int Variable2=-1;
//--- representation of numbers as aligned strings
string str1=StringFormat("Variable1=% 03i",Variable1);
string str2=StringFormat("Variable2=% 03i",Variable2);
//--- output the results
Alert(str1);
Alert(str2);

このコードの実行後、str1 変数には文字列 『変数1= 01』(スペース付文字列)が、str2 変数には文字列『変数2= 01』が入ります。

StringFormat()に類似する関数があと2つあります。それは PrintFormat() および printf() で、処理に関してはまったく同じです。StringFormat() 関数と唯一異なる点は Print() 関数に似た方法でジャーナルにテキストを出力することです。

上で述べられたことがらは数字をアウトプットするためのフォーマットに関する多くの課題を解決する最低限ですが、実際、StringFormat() 関数はもっと多くの機能性を提供します。
 

異なる言語でのメッセージ

StringFormat() 関数は異なる言語でメッセージをプリントするひじょうに便利な機能を伴うプログラムを強化する期間を提供します。異なる言語とは端末に設定されたインターフェース言語に依存するものです。

TERMINAL_LANGUAGE 識別子を伴うTerminalInfoString() 関数を呼ぶことでどのインターフェース言語が設定されているか確認することができます。プログラム実行時、インターフェース言語に応じてフォーマット文字列を準備し、プログラムでそれを使用します。以下は上記機能が実装された Expert Advisor のテンプレートです。

//--- variable for a format string
string FormatString;
//+------------------------------------------------------------------+
//| Handling the Init event                                          |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- get the format string
   FormatString=GetFormatString();
//--- additional call in case you want to ensure that the Expert Advisor operates at least once at weekends
   OnTick();
   return(0);
  }
//+------------------------------------------------------------------+
//| Handling the Tick event                                          |
//+------------------------------------------------------------------+
void OnTick()
  {
   int Variable1,Variable2,Variable3;
   Variable1=MathRand()%10;        // Random number from 0 to 10
   Variable2=MathRand()%10;        // Another random number
   Variable3=Variable1+Variable2; // Sum of numbers
//--- output the results
   Alert(StringFormat(FormatString,Variable1,Variable2,Variable3));
  }
//+------------------------------------------------------------------+
//| Determining the format string                                    |
//+------------------------------------------------------------------+
string GetFormatString(void)
  {
   string Language=TerminalInfoString(TERMINAL_LANGUAGE);
//--- language check
   if(Language=="Russian") return("%i плюс %i равно %i");     // Russian
   if(Language=="Spanish") return("%i más %i es igual a %i"); // Spanish
//--- English - in all other cases
   return("%i plus %i equals %i");
  }

Expert Advisor は2つの無作為な数を合計し、その処理に従いメッセージを出力します。たとえば、『1 たす2 は 3』などです。

文字列のアウトプットに関しては以上です。ここから少しばかり複雑な、しかしもっとおもしろい文字列操作に進みます。

 

文字列の作業についての主要な関数

文字列がプログラムのプロパティウィンドウでインプットされ、ファイルから読み出されるなら、不要なスペースを持っている可能性があります。それらはユーザーの単なる不注意かもしれませんし、または都合が良いために表示されるのかもしれません。いずれにしても文字列を使用する前に左右の端にあるスペースを削除することをお薦めします。このために MQL5 は2つ関数を備えています。 StringTrimLeft()(左端のスペース削除)およびStringTrimRight() (右端のスペース削除)です。スペース以外にもこれら関数はタブと改行文字を消去します。文字列の作業時には一度に両端のスペースを削除する必要がよくあります。よってこれを自走する関数はひじょうに便利です。

string Trim(string Str)
  {
   StringTrimLeft(Str);
   StringTrimRight(Str);
   return(Str);
  } 

実数を入力する際、ユーザーは点の代わりにコンマを使用しがちです。実数を扱う場合、小数点記号として点とコンマを両方使えるようにする機能を持つ必要があります。ある文字列を別の文字列と置き換えるには、StringReplace() 関数を使います。

string str="123,456";
//--- replace a comma with a dot
StringReplace(str,",",".");
double Value=StringToDouble(str);
//--- output the results
Alert(DoubleToString(Value));

"," をwith "."と置き換えないなら、文字列を数字に変換するとき、数字の端数部分は切り捨てられます。

連続したスペースを1個のスペースに置き換える必要があるかもしれません。これには、まず tab 文字をスペースと置き換え、それからスペースが1個になるまで2個のスペースを1個と置き換えます。

string str="Column-1 \t Column-2 \t Column-3";
//--- replace the tab character with a space
StringReplace(str,"\t"," ");
//--- get one space instead of the series of spaces
while(StringReplace(str,"  "," ")>0){}
//--- output the results
Alert(str);

StringReplace() 関数は置換が行われた回数を返します。エラーの場合は1を返します。よって、すべての連続したスペースが1件につき残される1個のスペースと置き換わるまでゼロより大きい値を返し続ける関数を伴うループを継続します。ループ本体はコードを持ちません。各反復でループ条件を確認する際には StringReplace() 関数を呼びます。

StringReplace() 関数により異なる長さの従属文字列を置き換えることができます。

string str="Programming in MQL5!";
//--- replace the substring, output the results
StringReplace(str,"in MQL5","for MetaTrader 5");
Alert(str);
//--- reverse replacement, output the results
StringReplace(str,"for MetaTrader 5","in MQL5");
Alert(str);

このコードを実行する際、最初の置き換え後、str 変数は『MetaTrader 5向けプログラミング』を持つ文字列を取得し、二番目の置き換えに続いて、『MQL5でのプログラミング!』を持つ文字列を取得します。

StringFind() 関数は従属文字列の検索に使用されます。この関数は、ある文字列内で生じる最初の従属文字列の指数を返します。渡される最初のパラメータは検索が行われる文字列です。二番目のパラメータは対象の従属文字列を判断します。また、三番目のパラメータ(オプション)は検索開始位置を決めることができます。三番目のパラメータが指定されていなければ、関数はその値が 0、すなわち検索が文字列の一番初めから開始される、として処理します。『MQL5でのMetaTrader 5向けプログラミング』で従属文字列 "5" の位置を見つけます。

string str="Programming in MQL5 for MetaTrader 5";
//--- get the position of the character
int Pos=StringFind(str,"5");
//--- output the results
Alert(IntegerToString(Pos));

このコードの実行後、Pos 変数の値は 23となります。従属文字列 "5" は合計2度出ていますが、関数は最初に出た位置しか返しません。単純に文字列を見て位置を数えたら、24を取得するはずです。問題は、この関数が1ではなくゼロから数え始めることです。対象の従属文字列がの次列内に見つからなければ、関数は -1を返します。

従属文字列が最後に出る位置を見つける必要がある場合もあるでしょう。この場合は、カスタム関数、StringFindRev() を書く必要があります。ループ内で最初に出る従属文字列の検索を始め、そして見つかった位置によって検索開始位置を移動していく、などです。

int StringFindRev(string Str,string Find)
  {
//--- the pos variable for the returned value
   int pos;
//--- auxiliary variable initialized to -1,
//--- in case the substring is not found in the string
   int tmp=-1;
//--- loop. It will be executed at least once
   do
     {
      //--- assign the last known position of the substring
      pos=tmp;
      //--- continue searching (using the third parameter of the function)
      tmp=StringFind(Str,Find,tmp+1);
     }
   while(tmp!=-1); // If the substring is not found in the remaining part of the string, the loop 
                   // is terminated and the pos variable stores the last
                   // known position
//--- return the position
   return(pos);
  }
この関数を使ってみます。
string str="Programming in MQL5 for MetaTrader 5";
//--- call the function for searching for a position of the last occurrence of the character in the string
int pos=StringFindRev(str,"5");
//--- output the results
Alert(pos);

このコードの実行後、Pos 変数は値、 40を取得します。
StringSubstr() 関数は既定位置から指定長の従属文字列を取得するのに使用されます。ポジション23から長さ1の従属文字列を取得します。

string str="Programming in MQL5 for MetaTrader 5";
//--- get the substring of the given length from the given position
string str2=StringSubstr(str,23,1);
//--- output the results
Alert(str2);

結果の値は "5"です。

ここまで主要な関数を考察してきました。リストアップした文字を文字列から削除する便利な関数を書くのにそれらを利用します。関数は原文字列とそこから削除する文字のリストである文字列を受け取ります。

string TrimL(string Str,string List="\t\n ;")
  {
//--- variable for one character of the Str string
   string ch;
   int Len=StringLen(Str);
   int i=0;
//--- loop iteration over all characters of the Str string
   for(;i<Len;i++)
     {
      //--- the next character of the Str string
      ch=StringSubstr(Str,i,1);
      //--- if this character is not on the List list, the string should start from this position 
      if(StringFind(List,ch,0)==-1)
        {
         break; // terminate the loop
        }
     }
//--- get the substring and return it
   return(StringSubstr(Str,i));
  }

この関数は、デフォルトでタブおよび改行文字、またスペースとセミコロン ";" を削除します。

右端で削除するための同じ関数です。

string TrimR(string Str,string List="\t\n ;")
  {
//--- variable for one character of the Str string
   string ch;
   int Len=StringLen(Str);
//--- characters in the string are numbered from 0, so the last character index is one less than the string length
   int i=Len-1;
//--- loop iteration over all characters of the Str string
   for(;i>=0;i--)
     {
      //--- the next character of the Str string
      ch=StringSubstr(Str,i,1);
      //--- if this character is not on the List list, the string should start from this position 
      if(StringFind(List,ch,0)==-1)
        {
         break; // terminate the loop
        }
     }
//--- get the substring and return it
   return(StringSubstr(Str,0,i+1));
  }

この関数もデフォルトでタブおよび改行文字、またスペースとセミコロン ";" を削除します。それはCSV ファイルを読むときに便利であることが判ります。これらファイルの中では、文字列の右端に数多くのフィールド分離記号(通常セミコロン ";")があるかもしれません。

大文字および小文字、たとえば "А" と "а" は人間にとっては同じ意味を持ちます。ですがコンピュータはそれらを2つのまったく異なる文字として扱います。SymbolInfoDouble() 関数を使ってマーケットデータを要求するとき "EURUSD" の代わりに "eurusd" と書いたとしたら、関数は要求する値を返しません。これはプロパティウィンドウにシンボル名を入力するとき起こりやすい事例です。MQL5では関数 StringToLower() (小文字に変更)また StringToUpper() (大文字に変更)を使用して大文字小文字に変えることができます。

string str="EuRuSd";
string str1=str;
string str2=str;
//--- change the case of strings
StringToUpper(str1);
StringToLower(str2);
//--- output the results
Alert(str1," ",str2);

このコードの実行後、str1 変数は "EURUSD"を持つ文字列を、str2 変数は "eurusd"を持つ文字列"を格納します。
それぞれのケースに配慮せず文字列を比較する必要があれば、それにStringCompare() 関数が最適です。関数の最初の2つのパラメータは比較のための文字列です。三番目のパラメータは、それぞれのケースを配慮して(真)または配慮せず(偽)文字列が比較されるべきかを判断します。

int Result=StringCompare("eurusd","EURUSD",false);
Alert(Result); 

関数が 0を返せば、文字列は同一ということです。この関数は、最初の文字列が二番目の文字列より小さければ -1 を、大きければ 1 を返します。『大きい』、『小さい』はアルファベット順に格納されるときの文字列の状態を言います。ここで文字 "b" は "a"より大きいとされます。

int Result=StringCompare("a","b",true);
Alert(Result); 

この場合、関数は -1を返します。

その他の関数に話を続けていく前に、ここで簡単な理論的脱線をします。
  

ヒトからみた文字列とコンピュータから見た文字列

ヒトにとって文字列とは何かというとひじょうに明白です。文字で構成されたテキストです。ヒトに比べ、コンピュータは構造がいくらかシンプルで、扱うのは数字だけです。コンピュータは画像、文字列、何もかもを数字ととらえます。文字列は一文字が一つの数字に対応する数字の羅列です。むしろ別のコードに対応する別の文字、などコードの羅列です。これらコードは ASCII コード(American Standard Code for Information Interchangeの短縮形)と呼ばれています。以降、256個のコードを持つ ASCIIを拡大した意味で、 ASCII という用語を使っていきます。よってコンピュータの『アルファベット』は256文字で構成されている、と言えます。異なる人々と言語に異なるアルファベットがあるように、コンピュータには多様な文字セット、いわゆるコードページがあります。ロシアのコンピュータユーザーはたいていが Windows-1251、ラテン文字とキリル文字、数字、句読点、その他記号を持つ文字エンコードを使用します。図1は Windows-1251 のコードページです。


図1 Windows-1251 コードページ

最初の32文字は表示されません。制御文字だからです。表示されませんが、その他の文字表示に影響を与えます。たとえば、タブ(コード9)、行送り(コード10)などです。

中央ヨーロッパ言語でテキストを表現するのに使用されるエンコードは Windows-1250 (図2)です。


図2  Windows-1250 コードページ

コード 192 から始めると、そこではコードページ 1251 はロシア語のアルファベットが特徴となっており、ヨーロッパ言語でのコードページ 1250 は発音区別語(音声値におけるわずかな変化を判断する発音区別符を伴う文字)を持つことに注意が必要です。

256 文字は数量としては非常に小さいものです。問題が起こるのは、テキストが複数言語で書かれる必要がある場合です。たとえばロシア語とフランス語(ひじょうに多くの発音区別語を持ちます)、または英語とアラビア語(その他言語の文字とひじょうに異なる文字です)などです。また、中国語や日本語のように漢字の文字列もあります。そこには何千個もの文字があり、それが難しいのはより明確です。なんらかの方法によって、コードページにインクルードされていない文字をエンコードする必要があるでしょう。HTMLに詳しい方は標準的でない文字を HTML ページに挿入する機能をご存じのことと思います。たとえば、 &Agrave À を表示するのに使用され、&Aacuteは Áを表示するのに使用される、などです。

1文字が1バイト(番号0~255)ではなく2バイトにエンコードされ、トータル65,536文字となる Unicode エンコードの使用が一般的となりました。この文字セットには世界に存在するすべてのアルファベット、図3に示されるもっとも一般的な漢字も含まれています(適切なフォントをお手持ちのコンピュータにインストールする必要はありますが)。

図3  異なるアルファベットと漢字 

図3  異なるアルファベットと漢字

MQL5 の文字列は Unicode を使用してエンコードされます。すなわち、文字列内の文字は0から 65535の数字で表すことができるのです。コード 0 ~ 127 の文字は ASCII と Unicode で共通です。テキストファイルは ASCII または Unicode を使ってエンコードされるテキストを持ち、その結果、ASCII および Unicode の文字列に連携する MQL5 の機能性は異なります。

 

文字列を配列に変換、また配列から文字列への変換

文字列で作業する際は関数 StringLen()、StringFind()、StringSubst() 、 StringReplace() があれば実際のタスクの大部分をこなすには十分です。ただ、暗号化、データの圧縮、チェック値の計算など数字として扱うのがずっと簡単なタスクもあるでしょう。そのタイプのタスクは日々行われるものではないとしても、いつか取り組む必要があるかもしれません。配列に変換されるべき文字列を必要とするより重要なタスクもあります。すなわち、Windows API (Application Programming Interfaces) 関数に文字列パラメータを渡すタスクです。

文字列を Unicode 配列に変換するには StringToShortArray() 関数を、ASCII 配列に変換するにはStringToCharArray() 関数を使います。

string str="MetaTrader 5";
//--- converting the string to a Unicode array
short sha[];
StringToShortArray(str,sha);
//--- converting the string to a ASCII array
uchar cha[];
StringToCharArray(str,cha);
//--- flag the difference
bool Dif=false;
//--- compare the arrays element by element
for(int i=0;i<StringLen(str);i++)
  {
   if(sha[i]!=cha[i])
     {
      Dif=true;
     }
  }
//--- output the results
if(Dif) Alert("Different");
else    Alert("Identical");

上記例で関数StringToShortArray() と StringToCharArray() を使用して取得した配列が同一のものであれば、『同一です』のメッセージを持つウィンドウがポップアップし、配列に相違があれば、『異なります』のメッセージが表示されます。文字列『MetaTrader 5』につしては、配列は同一です。なぜなら文字列は文字コード 127までの文字で構成されているからです。

文字コード 127以上は少々異なります。StringToShortArray() 関数の処理結果はつねにどこでも同じです。一方、StringToCharArray() 関数の処理結果はオペレーションシステムの地域設定に依存します。

Windows 7では、システム言語は「コントロールパネル」-「地域と言語」-「表示言語変更」で選択可能です。

以下の例を見ます。コードページ 1251では、コード 192は文字 "А" (ロシア語アルファベットの最初の文字)に相当します。一方、エンコード 1250 の同じコードは文字 "Ŕ" (チェコ語のアルファベットの文字でもっとも一般的にしらえっるひとつ)に対応しています。StringToShortArray() 関数を使用するとき、文字 "А" はつねにコード1040で、先の文字 "Ŕ" はコード 340です。システムがロシア語に設定されていると、 StringToCharArray() 関数を使うとき、文字 "А" がコード 192 (正)に対応し、文字 "Ŕ" はコード 82 (ラテン語の "R")に対応します。ただしシステムがチェコ語に設定されていれば、文字 "А" はコード63(クエスチョンマーク)、文字 "Ŕ" はコード192(正)に対応します。発音区別符号を持つ文字はラテン文字の近い文字に置き換えられ、あまり一般的でない文字はクエスチョンマークに置き換えられます。

また文字列のサイズと結果の配列に注意を払います。

int StrLen=StringLen(str);
int shaLen=ArraySize(sha);
int chaLen=ArraySize(cha);
//--- output the lengths
Alert(StringFormat("%i, %i, %i",StrLen,shaLen,chaLen));

配列内のエレメント数は文字列内の文字数より1大きくなります。これは文字列の最後がコード 0の文字でマークされていることに関連します。この文字は文字列内には表示されませんが、表示されている文字列の終わりを示すことでコンピュータにとっては意味があります。文字列の長さに対応した量で一度に1バイト(文字)の割合でつねにデータ交換が行われるのではありませんが、コード 0 の文字によりあらゆる場合に文字列の終わりを決めることができるのです。同じゼロが問題を起こすこともあります。たとえば、特定の文字が暗号化するときやアルゴリズムの圧縮を行うときにコード 0 を持つ文字に変換される可能性があります。このような場合、配列を文字列に変換しなおすなら、文字列は完全なものとはならないでしょう。このタイプのタスクには特殊な方法が必要ですが、これは本稿で述べるものではありません。

配列から文字列への逆変換は関数 ShortArrayToString() および CharArrayToString() を使用することで可能です。

//--- convert an array of Unicode codes to a string
short sha[]={85,110,105,99,111,100,101};
string str1=ShortArrayToString(sha);
//--- convert an array of ASCII codes to a string
uchar cha[]={65,83,67,73,73};
string str2=CharArrayToString(cha);
//--- output the results
Alert(str1+" "+str2);

上記コードの結果str1 変数は『Unicode』文字列を、str2 変数は『ASCII』文字列を 格納します。

あと2つ類似する関数があります。:ShortToString()CharToString()です。これらは short タイプまたは char タイプのシングル変数を1文字の文字列に変換します。CharToString() 関数には多大な実用的価値があります。異なるシンボルを表示することを可能にするグラフィカルオブジェクトである OBJ_ARROW は価格軸に縦向けに、時間軸に横向け固定されているため、チャートをスクロースするとシンボルが移動します。Wingdings フォントと共に OBJ_LABEL を使うことで画面の座標に固定された異なるシンボルを表示することができ、そのためさまざまな情報パネルを作成することができるようになります。Wingdings シンボル表で必要なシンボルを見つけ、そのコードを OBJ_LABEL グラフィカルオブジェクトを使ってのちに表示する文字列に変換します。

   ObjectCreate(0,"lbl",OBJ_LABEL,0,0,0);           // create the LABEL graphical object
   ObjectSetInteger(0,"lbl",OBJPROP_XDISTANCE,100);   // set the X-coordinate
   ObjectSetInteger(0,"lbl",OBJPROP_YDISTANCE,100);   // set the Y-coordinate
   ObjectSetInteger(0,"lbl",OBJPROP_FONTSIZE,20);     // set the size
   ObjectSetString(0,"lbl",OBJPROP_FONT,"Wingdings"); // set the Wingdings font
   string Icon=CharToString(37);                   // 37 - the bell
   ObjectSetString(0,"lbl",OBJPROP_TEXT,Icon);       // set the displayed text

このコードの実行結果として、チャート上にベル型のアイコンが表示されます。チャートをスクロールしてもベルは元の場所に留まります。

文字コードと関連するあと2個の関数は StringGetCharacter() および StringSetCharacter()です。それらは Unicode コードで動作します。StringGetCharacter() 関数により文字列内の既定位置で文字コードを取得することができます。

string str="L5";
//--- get the Unicode code of the character at the given position in the string
ushort uch1=StringGetCharacter(str,0);
ushort uch2=StringGetCharacter(str,1);
//--- output the results
Alert(StringFormat("%i, %i",uch1,uch2));

このコードの実行後、uch1 変数は値 76 を、uch2 変数は値" 53を格納します。

StringSetCharacter() 関数は既定位置で文字コードの変更を可能にします。また文字列の最後に文字を追加することもできるようになります。

string str="MQ5";
//--- replace the character at the given position in the string with the Unicode character corresponding to the passed code
StringSetCharacter(str,2,76);
Alert(str);
//--- add the Unicode character corresponding to the passed code to the end of the string
StringSetCharacter(str,3,53);
Alert(str);

このコードの実行時、str 変数は『MQ5』の代わりにまず『MQL』を、次に『MQL5』を格納します。

 

API 関数の呼び出し

API 関数の中にはその変数として文字列パラメータを使うものがあります。たとえば、第三者アプリケーション WinExec への関数は第一パラメータとして uchar タイプの配列を使用します。

#import "kernel32.dll"
int WinExec(uchar &Path[],int Flag);
#import 

Windowsの標準的プログラムである notepad.exe (Notepad)を実行してみます。notepad へのパスを uchar タイプの配列に変換します。

string PathName="C:\\WINDOWS\\notepad.exe";
uchar ucha[];
StringToCharArray(PathName,ucha);
int x=WinExec(ucha,1); 

この関数処理により Notepad テキストエディタが開きます。

API 関数で文字列パラメータを使用するもう一例は Unicodeを使ってウィンドウにメッセージをプリントするMessageBoxW関数です。この理由でパラメータとして ushort タイプの配列を渡します。

#import "user32.dll"
int MessageBoxW(int hWnd,ushort &szText[],ushort &szCaption[],int nType);
#import

ここでこの関数を使いウィンドウ内にメッセージをプリントします。

ushort arr[];
ushort capt[];
//--- convert
StringToShortArray("Programming in MQL5 for MetaTrader 5.",arr);
StringToShortArray("Message",capt);
//--- print the message
MessageBoxW(0,arr,capt,0);

このコードの実行結果として次のメッセージを伴うウィンドウが表示されます。:『MQL5でのMetaTrader 5用プログラミング』

上記例で ushort タイプ配列の使用は必要ありません。ただ関数パラメータとして文字列を渡すだけでも可能です。

#import "user32.dll"
int MessageBoxW(int hWnd,string szText,string szCaption,int nType);
#import
//+------------------------------------------------------------------+
//| Function for running the script                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   MessageBoxW(0,"Programming in MQL5 for MetaTrader 5","Message",0);
  }

このコード実行結果は上記と同じです。ただし、正しいメッセージをプリントするためには、関数パラメータとして uchar タイプの配列は使用できません。

#import "user32.dll"
int MessageBoxW(int hWnd,uchar &szText[],uchar &szCaption[],int nType);
#import
//+------------------------------------------------------------------+
//| Function for running the script                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   uchar arr[];
   uchar capt[];
//--- convert
   StringToCharArray("Programming in MQL5 for MetaTrader 5.",arr);
   StringToCharArray("Message",capt);
//--- print the message
   MessageBoxW(0,arr,capt,0);
  }

コードはエラーなく実行され、ポップアップウィンドウが表示されますが、メッセージはゆがめられています。

ASCII エンコード(たとえば uchar タイプの配列をすでに取得している場合)で文字列をプリン度する必要がある場合、類似の関数 MessageBoxA があります。メッセージを正しく表示するには、文字列パラメータとして uchar タイプ配列のみ関数に渡されます。この関数をインポートし、メッセージをプリントするために呼び出します。

#import "user32.dll"
int MessageBoxA(int hWnd,uchar &szText[],uchar &szCaption[],int nType);
#import
//+------------------------------------------------------------------+
//| Function for running the script                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   uchar arr[];
   uchar capt[];
//--- convert
   StringToCharArray("Programming in MQL5 for MetaTrader 5",arr);
   StringToCharArray("Message",capt);
//--- print the message
   MessageBoxA(0,arr,capt,0);
  }

再び正しいメッセージ『MQL5でのMetaTrader 5用プログラミング』を取得します。

基本的に文字列に関連する多くの WinAPI 関数にはオプションが2つあります。SCII 文字列と連携するオプションと Unicode 文字列と連携するオプションです。

関数を呼べるようにするためには、ターミナル設定(ターミナル-メインメニュー-ツール-オプション-Expert Advisors-DLL インポートを許可する)で DLLの使用を有効にするか、文字列、Expert Advisor 、インディケータを実行するときプロパティウィンドウの依存タブで『DLL インポートを許可する』にチェックを入れます。適切な文字列のプロパティを指定し、文字列用にプロパティウィンドウを開けるようにします。

#property script_show_inputs

 

無制限パラメータインプット

ユーザーはプロパティウィンドウでパラメータを入力します。その際、パラメータをセミコロンで区切ります。

input string Lots="0.1; 0.2; 0.3; 0.5";

上記文字列をダブルタイプの変数配列に変換する必要があります。

MQL5では、文字列は StringSplit() 関数によって分割することができます。関数に渡される最初のパラメータは文字列、二番目のパラメータは分離記号の ASCII コード、三番目に渡されるパラメータは関数処理結果を格納する配列です。ASCII コードを決めるにはひじょうにシンプルな方法があります。必要な文字をクオーテーションマークで囲むのです。

int Code='A';
Alert(IntegerToString(Code)); 

このコードの結果、Code 変数は値 65を格納します。これはラテン文字では "A"にあたる ASCII コードです。

分離関数の問題の解決策を書き、必要なときにそれを使用できるようにします。渡される最初のパラメータは文字列で、二番目のパラメータは参照によって返される配列です。関数のコードは以下にあります。詳細コメントがついていますので、それ以上の説明は必要ないでしょう。

int ParamsToArray(string Str,double &Params[])
  {
//--- delete spaces at the ends
   StringTrimLeft(Str);
   StringTrimRight(Str);
//--- if the string is empty
   if(StringLen(Str)==0)
     {
      ArrayFree(Params); // free the array
      return(0);         // function operation complete
     }
//--- auxiliary array
   string tmp[];
//--- split the string
   int size=StringSplit(Str,';',tmp);
//--- delete spaces at the ends for each element of the array
   for(int i=0;i<size;i++)
     {
      StringTrimLeft(tmp[i]);
      StringTrimRight(tmp[i]);
     }
//--- delete empty elements from the array (user could accidentally 
//--- put the separator two times in a row or at the end of the string)
   for(int i=size-1;i>=0;i--)
     {
      if(StringLen(tmp[i])==0)
        {
         ArrayCopy(tmp,tmp,i,i+1);
         size--; // array size reduced
        }
     }
//--- scale the array according to the new size
   ArrayResize(tmp,size);
//--- replace commas with dots
   for(int i=0;i<size;i++)
     {
      StringReplace(tmp[i],",",".");
     }
//--- prepare the array to be returned
   ArrayResize(Params,size);
//--- convert all elements to the double type and fill the array to be returned 
   for(int i=0;i<size;i++)
     {
      Params[i]=StringToDouble(tmp[i]);
     }
//--- the function returns the number of parameters
   return(size);
  }

 

文字列の多様な変数への変換

ParamsToArray() 関数は文字列をダブルタイプの変数に変換するのにStringToDouble() 関数を使いました。浮動小数点タイプに変換するのにも同じ関数を使用します。他の変数タイプい変換するのに用いられる標準関数が複数あります。

StringToInteger() 関数は文字列を整数変数に変換します。

string Str="12345.678";
//--- convert the string to an integer
long Val=StringToInteger(Str);
//--- inverse convert and output the results
Alert(IntegerToString(Val));

このコードの実行後、Val 変数は値 12345を格納します。端数部分は単純に切り捨てられます。

StringToTime() 関数は時刻の文字列表現を適切な数値に変換します。時間を指定しなければ、デフォルト値は "00:00"です。

string Str1="2012.11.02 22:00";
string Str2="2012.01.01";
//--- convert the string expression of time to the datetime type
datetime DateTime1=StringToTime(Str1);
datetime DateTime2=StringToTime(Str2);

StringToColor() 関数は色名(標準ウェブカラー)を適切な数値、または RGB コンポーネントの文字列に変換します。

string Str1="clrYellow";
string Str2="255,255,0";
color Color1=StringToColor(Str1);
color Color2=StringToColor(Str2); 

文字列を datetime タイプおよび color タイプに変換する方法がもう一つあります。それは特定の値を変数に割り当てる際に使用することが可能です。

datetime DateTime=D'2012.11.02 22:00';
color Color=C'255,255,0'; 

日付表記の前に"D" を書き、日付自体はクオーテーションマークの中いn入れます。色の文字列表記の前には文字 "С" を入れます。RGB コンポーネントはクオーテーションマークで囲み、コンマで区切ります。

 

通知の有効化

ユーザーは特定タイプの通知を有効にする連続した文字を入力します。この方法は有効化された通知のさまざまな組合せを取得するために使用することができます。警告通知は "а"、音声通知は "s"、Eメール通知は "e"、プッシュ通知は "p"に対応します。また、シグナルが確認されるバーを示すために文字列に 1 または 0 を加えることができます(インディケータでは有用なことがあります)。コードは最初のパラメータが参照で返される Shift 変数(バーの番号)と異なる通知方法に対応しているブールタイプの変数が続く文字列である関数として表記されます。コードを詳細コメントを伴って以下に提供します。

void NotifyOnOff(string Str,int &Shift,bool &Alerts,bool &Sounds,bool &EMail,bool &Push)
  {
//--- Convert the string to lower case to allow the user
//--- to use both lowercase and uppercase characters.
   StringToLower(Str);
//--- search for characters in the string
   Alerts=(StringFind(Str,"a")!=-1);    // "a" found
   Sounds=(StringFind(Str,"s")!=-1);    // "s" found
   EMail=(StringFind(Str,"e")!=-1);     // "e" found
   Push=(StringFind(Str,"p")!=-1);      // "p" found
//--- search for zero
   if(StringFind(Str,"0")!=-1) Shift=0;  // "0" found in the string
   else                       Shift=1; // by default
  }

プロパティウィンドウ内の5個の変数の代わりに1個で十分です。 

 

文字列バッファ

まだじっくり考察すべき標準関数が3つあります。:StringInit()StringFill()StringBufferLen()です。

StringInit() 関数は同じ文字を指定された数、文字列に書き込みます。

string str;
StringInit(str,10,'|');
Alert(str); 

このコードの実行後、str 変数は "||||||||||"の文字列を格納します。文字はs ASCII コードによって指定されます。すなわち文字はクオーテーションマークで囲む必要があります。

StringFill() 関数は文字列サイズを変えずに同じ文字を複数文字列に書き込みます。以下は前出の例の続きです。

StringFill(str,'/');
Alert(str); 

これに続きstr 変数は "//////////"の文字列を格納します。

コード 0 (文字列の終わり)の文字で文字列を書きます。

StringFill(str,0); 
文字列サイズ確認
int Length=StringLen(str);
Alert(IntegerToString(Length)); 

サイズは 0 で、コード 0 を伴う文字はの次列の開始位置にあります。バッファサイズ確認

int BLength=StringBufferLen(str);
Alert(IntegerToString(BLength)); 

バッファサイズは 0 とは異なり、最初の文字列のサイズを越えます。文字列に割り当てられるメモリはもうしぶんありません。ここでバッファサイズ範囲内に収まっている文字列に値を割り当てる際、メモリの再配分は必要なく、値はひじょうに素早く割り当てられます。バッファサイズが減っていないことを確認するために、割当てではなく文字列に新しい値を追加します。

str+="a"; 

文字列長はこれで1となり、バッファサイズに変更はありません。この方法で文字列の処理をいくぶんスピードアップすることができます。文字列は冒頭にコード 0 を伴う文字を挿入することで宣言できます。

StringSetCharacter(str,0,0); 

 

おわりに

本稿の主題は MQL5 言語、すなわち Expert Advisors およびインディケータ、の主要目的にわずかに関連しているだけでさして重要ではないとお考えかもしれません。ですが、ここで導かれたことは言語が提供する文字列に関わる広範な機能性から端を発した、広範囲に及ぶ内容です。たぶんExpert Advisors およびインディケータをプログラミングする場合はたいてい、文字列を扱う必要はないでしょうが、それでも将来必要となることもありえます。本稿を読めば、必要に応じて必要な場面で文字列を使用する準備は万端です。関数を学習するために時間を無駄にすることもありません。必要なことを簡単に行うことができるのです。

目的、重要性、使用頻度に応じて関数を分類し、本稿で提供された情報を要約します。

  1. StringLen()、StringFind()、StringSubstr()、StringReplace()、 StringSplit() は文字列長を決定し、従属文字列を検索、取得、置換するのに使用する主要な基本的関数です。また、文字列分割も行います。
     
  2. StringTrimLeft()、StringTrinRight()、StringToLower() and StringToUpper() は文字列末尾のスペースを削除し、大文字小文字を変更するのに使用されるひじょうに便利な予備関数です。
     
  3. ColorToString()、DoubleToString()、EnumToString()、 IntegerToString()、TimeToString()、StringFormat() は数値を文字列に変換する関数です。
     
  4. StringToColor()、StringToDouble()、StringToInteger()、 StringToTime() 、StringCompare() は文字列を数値変数に変換する関数です。
     
  5. StringAdd()、StringConcatenate() は効果的な方法でスペース内で文字列を合計したり組み合わせるのに使用できる関数です。
     
  6. ShortToString()、ShortArrayToString()、StringToShortArray()、CharToString()、CharArrayToString()、StringToCharArray() はひじょうに複雑な文字列操作を必要とするタスクを行う際便利な配列としての文字列と連携する関数です。上記リストから特に重要な関数を2個指摘することができます。 

    • CharToString() は Wingdings フォントと共にグラフィカルオブジェクトを扱うために使用されます。
    • CharArrayToString() は API 関数を呼ぶとき文字列パラメータを準備するのに使用されます。

  7. StringSetCharacter()、StringGetCharacter()、StringInit()、StringFill()、StringBufferLen() は補助的関数です。

 

添付ファイル

  1. IncStrFunctions.mqh には関数 Trim()、StringFindRev()、 TrimL()、TrimR()、ParamsToArray()、NotifyOnOff() が含まれます。
  2. eMultiLanguageMessage.mq5 は異なる言語でのメッセージを対象とした Expert Advisor の一例です。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/585

添付されたファイル |
マシンラーニング:サポートベクターマシンをトレーディングで利用する方法 マシンラーニング:サポートベクターマシンをトレーディングで利用する方法
「サポートベクターマシン」は生物情報学分野でこれまで長く利用され、複雑なデータセットを評価し、データ分類すに利用できる有用なパターンを抽出するため数学を利用しています。本稿はサポートベクターマシンとは何か、それがどのように役立つか、またなぜ複雑なパターンを抽出するのに便利かを考察します。そしてそれをマーケットに応用する方法、およびトレードを行う上で将来役立つであろう使用方法を調査します。また「サポートベクターマシン学習ツール」を使用し、読者のみなさんがご自身のトレーディングで実験することができる実用例を提供します。
MetaTrader 4とMetaTrader 5のシグナルプロバイダーになる方法 MetaTrader 4とMetaTrader 5のシグナルプロバイダーになる方法
取引シグナルを提供して収入を得たいですか?MQL5.comのWebサイトに販売者として登録し、取引口座を指定し、トレーダーがあなたの取引に購読してコピーできるようにできます。
ポイントおよびグラフチャート化インディケータ ポイントおよびグラフチャート化インディケータ
現在マーケットの状況に関する情報を提供するチャートは数多くあります。「ポイント」や「グラフ」チャートのようにそれらの多くは遠い過去の遺産です。本稿は実時間のインディケータを用いて「ポイントとグラフ」チャート例について述べます。
インディケータエミッションの積分特性計算 インディケータエミッションの積分特性計算
インディケータエミッションはマーケットリサーチでほとんど研究されていない分野です。時間依存性データのひじょうに大きな配列を処理することで起こる分析の難しさがその主な理由です。既存のグラフ分析は資源集約的に過ぎ、そのためエミッションの時系列を利用する簡素なアルゴリズムの開発をもたらしました。本稿では視覚的(直観的イメージ)分析がどのようにエミッションの積分特性の研究に置き換えることができるのかを示します。トレーダー、自動売買システムの開発者双方に興味深いものとなることでしょう。