MQL5 - Working with strings

Hello everyone! We continue studying MQL5 from scratch, and today we will talk about strings and string functions. I remind you that the lessons are aimed at people unfamiliar with programming in MQL5 and with programming in general, and therefore, having started from the basics, we gradually increase the complexity of the material being presented.

Previous lessons

    As you remember, the string type is used to store text strings in MQL5. A string constant is a sequence of Unicode characters enclosed in double quotation marks.

    The MQL5 language has very broad and convenient functionality for working with strings. Most often, when programming expert advisors and indicators, strings are used to form informational messages about the fulfillment of certain conditions, about trading operations, and so on.

    In addition, writing and reading files is carried out with string variables. Of course, there is another way to work with files, binary, which provides reading and writing numeric variables and arrays. But if the data volumes are small, it is better to use text files and strings. In this case, the process of developing the program is simplified, since direct control of the data is provided. In text files, the data looks exactly the same as it does inside the program.

    The use of strings can expand the program's capabilities for entering parameters in cases where the required number of parameters is unknown in advance. As an example: lot sizes for averaging add-ons. In this case, the values can be written into one string through some separator, for example, through a semicolon:

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

    Then, when the expert is initialized, the string is easily split, and an array of numeric values is filled using one of the string functions built into MQL5. There is, of course, a downside here: such string parameters cannot be iterated during optimization. But there may well be other cases when parameter optimization is guaranteed not to be needed, for example, a list of currency pairs on which the expert will work, especially if it is multi-currency (for example, trades a basket of currencies).

    We already covered this data type in the initial lessons, but today we will review it and deepen our knowledge.

    Declaring a string variable

    Like all other types of variables, string variables can not only be declared:

    string str;

    but can also be declared immediately with an assigned value (initialized with a value):

    string str="Lyuboy tekst";

    There are no restrictions on string length. Long strings can, for convenience, be written on several lines:

    string str= "Dlinnaya stroka mozhet "
                "byt zapisana v neskolkikh "
                "strochkakh";

    With such initialization, the variable str will contain the string "A long string can be written on several lines".

    Here, a little ahead of ourselves, it should be noted that the value of a string variable declared without parameters is not identical to an empty string:

    string str="";

    You can verify this:

    string str1;
    string str2="";
    Print(str1==str2);

    When this code is executed, a window with the message "false" will open. An uninitialized string variable has the value NULL, and it differs from the empty string "". This should be remembered! When working with strings, it is very often necessary to check whether the string is empty. Therefore, you should either follow the rule of initializing all strings with the empty string "", or perform two checks: inequality to "" and inequality to NULL:

    if(str!="" && str!=NULL)
      {
       //--- chto-to delaem so strokoy
      }

    The first method is preferable, since it simplifies the check condition. 

    A similar check can be made by checking the size of the variable. The StringLen() function is used to determine the size:

    if(StringLen(str)!=0)
      { 
       //--- chto-to delaem so strokoy
      }

    String concatenation

    The main action that most often has to be performed with strings is their concatenation, that is, forming phrases from words. Concatenation is performed with the "+" sign:

    string str1,str2,str3,str4,str5;
    //--- prisvoenie znacheniy
    str1="Programmirovanie";
    str2="na MQL5";
    str3="dlya MetaTrader 5";
    //--- slozhenie strok
    str4=str1+" "+str2;
    str5=str1+" "+str3;
    //--- vyvod rezultatov
    Alert(str4);
    Alert(str5);

    After this code is executed, the variable str4 will contain the phrase "Programming in MQL5", and the variable str5 the phrase "Programming for MetaTrader 5". In this example, two strings were concatenated and the resulting string was assigned to another variable.

    Very often, an additional string is appended to the main string: 

    string str1,str2,str3;
    //--- prisvoenie znacheniy
    str1="Programmirovanie";
    str2="na MQL5";
    str3="dlya MetaTrader 5";
    //--- slozhenie strok s dobavleniem k osnovnoy stroke
    str1=str1+" "+str2;
    str1=str1+" "+str3;
    //--- vyvod rezultata
    Alert(str1);

    After this code is executed, the string str1 will contain the phrase "Programming in MQL5 for MetaTrader 5". In this example, something was appended to the main string str1 and the resulting result was assigned back to it. Such actions can be written a little more simply:

    str1+=str2;
    str1+=str3;
    Ili tak:
    str1+=str2+str3;

    The "+" sign to the left of the "=" sign means that the expression written to the right of the "=" sign is appended to the variable str1.

    You can also append a string to the beginning of the main string; this is done similarly to the penultimate example: the main string is added to the string being appended, and the resulting string is assigned to the main variable:

    string str1,str2,str3;
    //--- prisvoenie znacheniy
    str1="Programmirovanie";
    str2="na MQL5";
    str3="dlya MetaTrader 5";
    //--- slozhenie strok s dobavleniem stroki v nachalo
    str3=str2+" "+str3;
    str3=str1+" "+str3;
    //--- vyvod rezultata
    Alert(str3);

    Only now the phrase "Programming in MQL5 for MetaTrader 5" will be in the variable str3. The same thing can also be done in a single line: 

    str3=str1+" "+str2+" "+str3;

    In some cases, concatenation can be performed using the "," sign (comma). This happens when calling the functions Alert(), Print(), Comment():

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

    The final results when using this notation will be identical to using the "+" sign:

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

    In fact, the "," sign does not perform string concatenation; in all functions, the comma is a parameter separator. The same applies to the functions Alert(), Print(), Comment(). These functions have one required parameter and a large number of optional ones. Essentially, several parameters are passed to the function, and inside the function they are joined together. The maximum number of parameters is 64.

    In addition to using the "+" sign, the MQL5 language has specialized functions for string concatenation: StringAdd() and StringConcatenate(). According to the description of these functions in the reference manual, they allow strings to be joined more economically in terms of RAM usage and more quickly.

    StringAdd appends the specified substring to the end of the string in place.

    bool StringAdd(
    string& string_var, // stroka, k kotoroy dobavlyaem
    string add_substring // dobavlyaemaya stroka
    );

    If executed successfully, the function returns true, otherwise false. To get the error code, you need to call the function GetLastError().

    Example:

    void OnStart()
    {
    long length=1000000;
    string a="a",b="b",c;
    
    //--- pervyy sposob
    uint start=GetTickCount(),stop;
    long i;
    
    for(i=0;i<length;i++)
    {
    c=a+b;
    }
    
    stop=GetTickCount();
    Print("time for 'c = a + b' = ",(stop-start)," milliseconds, i = ",i);
    
    //--- vtoroy sposob
    start=GetTickCount();
    for(i=0;i<length;i++)
    {
    StringAdd(a,b);
    }
    
    stop=GetTickCount();
    Print("time for 'StringAdd(a,b)' = ",(stop-start)," milliseconds, i = ",i);
    
    //--- tretiy sposob
    start=GetTickCount();
    
    a="a"; // zanovo initsializiruem peremennuyu a
    for(i=0;i<length;i++)
    {
    StringConcatenate(c,a,b);
    }
    
    stop=GetTickCount();
    Print("time for 'StringConcatenate(c,a,b)' = ",(stop-start)," milliseconds, i = ",i);
    }

    StringConcatenate forms a string from the passed parameters and returns the size of the formed string. Parameters can be of any type. The number of parameters cannot be less than 2 and cannot exceed 64.

    int StringConcatenate(
    string& string_var, // stroka dlya formirovaniya
    void argument1 // pervyy parametr lyubogo prostogo tipa 
    void argument2 // vtoroy parametr lyubogo prostogo tipa
    ... // sleduyushchiy parametr lyubogo prostogo tipa
    );

    Returns the length of the string formed by concatenating parameters converted to the string type. Parameters are converted to strings according to the same rules as in the Print() and Comment() functions.

    Converting Various Variables to a String

    When forming a message string, it is very often necessary to add the values of numeric variables to it. To convert the values of integer variables (char, uchar, bool, short, ushort, int, uint, color, long, ulong, datetime) to a string, the function IntegerToString() is used:

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

    If you convert a variable of type bool, the string "0" (false) or "1" (true) will be returned; when converting variables of type color or datetime, a string with the numeric representation of the color or date will be returned (for example, "65535" for the yellow color clrYellow or "1325376000" for the date 2012.01.01 00:00).

    To convert floating-point variables (double, float) to a string, the function DoubleToString() is used. The second parameter of this function determines the precision (the number of digits after the decimal point):

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

    After executing this code, the variable str1 will contain the string "1.23", and the variable str2 will contain the string "1.235". Trimming to the specified number of digits works according to the principle of mathematical rounding.

    To convert date and time to a string in the standard format (understandable to a person), the function TimeToString() is used:

    datetime tm=TimeCurrent(); // Tekushchee vremya 
    string str1=IntegerToString(tm);
    string str2=TimeToString(tm);

    After executing this code, the variable str1 will contain a string with the numeric representation of time (the number of seconds since January 1, 1970), and str2 will contain formatted time, for example, "2012.11.02 22:00" (year, month, day, hours, minutes).

    When calling the TimeToString() function, it is possible to specify the date and time display format. The following options are possible:

    string str1="Data i vremya s minutami: "+TimeToString(tm);
    string str2="Tolko data: "+TimeToString(tm,TIME_DATE);
    string str3="Tolko vremya s minutami: "+TimeToString(tm,TIME_MINUTES);
    string str4="Tolko vremya s sekundami: "+TimeToString(tm,TIME_SECONDS);
    string str5="Data i vremya s sekundami: "+TimeToString(tm,TIME_DATE|TIME_SECONDS);

    MQL5 has a very convenient functional capability: creating enumerations, which in the program properties window are displayed as drop-down lists with a set of options. The values of such variables can also be converted to a string; for this, the function EnumToString() is used. Below is the script code demonstrating how this function works:

    //+------------------------------------------------------------------+
    //| Sozdanie perechisleniya                                            |
    //+------------------------------------------------------------------+
    enum EMode
      {
       OFF=0,
       Mode1 = 1,
       Mode2 = 2,
       Mode3 = 3 
      };
    //+------------------------------------------------------------------+
    //| Zapusk skripta                                                   |
    //+------------------------------------------------------------------+
    void OnStart()
      {
       EMode Value=1;
       //--- soedinenie strok
       string str="Znacheniyu "+IntegerToString(Value)+" sootvetstvuet punkt "+EnumToString(Value)+" perechisleniya EMode";
       //--- vyvod rezultata
       Alert(str);
      }

    A similar capability also exists for converting color variables. You can convert a color value to its name, for which the function ColorToString() is used:

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

    After executing this code, the variable str will store the string "clrRed". If the second parameter is set to false, the function will return a string with the values of the RGB components (red, green, blue):

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

    In this case, the variable str will store the string "255,0,0". If the color is not standard (not included in the web color set and, accordingly, has no name), then the ColorToString() function returns a string with the component values regardless of the value of the second parameter.

    There is one more way to convert variables: through type casting:

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

    When converting a variable of type bool in this way, the string will have the value " true" or "false": 

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

    Conversion of variables of type double and float is performed with maximum precision; only trailing zeros in the fractional part are discarded: 

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

    After executing this code, the string "0.1" will be stored in the str1 variable, and the string "0.123" in the str2 variable.

    Displaying Special Characters

    When initializing a string variable with a value, the assigned string is placed in double quotation marks so that the compiler can distinguish the string from program code. In order to place quotation marks inside the string, you need to indicate that in this case the symbol is used not for its direct purpose (as a symbol separating the string from the code), but as part of the string. To do this, you need to put a backslash before the quotation mark "\":

    string str1="Prosto tekst";
    string str2="\"Tekst v kavychkakh\"";
    //--- vyvod rezultatov
    Print(str1);
    Print(str2);

    Since the backslash is also a special character, to output it into a string you need to put one more backslash before it:

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

    After executing this code, there will be one "\" character in the string.

    A string can also contain a horizontal tab character, which is indicated by the symbols "\\t":

    string str="Kolonka-1\tKolonka-2\tKolonka-3";
    Print(str);

    In this case, the string "Column-1        Column-2        Column-3" will be stored in the str variable.

    With the help of the "\n" symbols, text can be output with line breaks, in several lines:

    string str="Stroka-1\nStroka-2\nStroka-3";
    Print(str);

    In this case, the result of executing the Print() function will be three lines of text.

    When outputting using the Alert() and MessageBox() functions, as well as when writing to a file, both symbols work: "\\t" and "\n". However, when outputting to a chart comment (the Comment() function), only the new line symbol "\n" works, while the tab symbol "\\t" is ignored. When outputting with the Print() function, the "\n" symbol also works (each part of the string is output on a separate log line), while the "\\t" symbol is replaced with a space. In the log file, which stores all messages output by the Print() function, the "\\t" symbol is replaced with a space.

    Template-Based String Formatting

    When constructing a string for output, it may be necessary to include the values of several numeric variables in it. This task can be solved by concatenating strings and converting numeric variables to strings, but in that case the line of code that forms the message will be very long and inconvenient for understanding and editing when making program modifications:

    //--- initsializatsiya peremennykh
    int Variable1=1;
    int Variable2=2;
    int Variable3=3;
    //--- dlinnoe soedinenie strok
    string str="Variable1 = "+IntegerToString(Variable1)+", Variable2 = "+IntegerToString(Variable2)+", Variable3 = "+IntegerToString(Variable2);
    Print(str);

    This task can be solved much more easily with the help of the StringFormat() function. The first parameter passed to this function is a message template in which the variable insertion positions are specified and their output format is defined. Then all variables are listed in the order in which they appear in the template: 

    //--- initsializatsiya peremennykh
    int Variable1=1;
    int Variable2=2;
    int Variable3=3;
    //--- bolee prostoe soedinenie strok
    string str=StringFormat("Variable1 = %i, Variable2 = %i, Variable3 = %i",Variable1,Variable2,Variable3);
    Print(str);

    Variable insertion positions are indicated by the "%" sign; the following symbol "i" in the example shown means that the variables should be output as integers. More precisely, "i" means signed integer variables (char, short, int, color), while "u" is used for unsigned integers (uchar, bool, ushort, uint). For variables of the long, ulong, and datetime types, you should additionally specify the variable bit width by writing "I64" before the type:

    string LongMin=StringFormat("%I64i",LONG_MIN);
    string LongMax=StringFormat("%I64i",LONG_MAX);
    string ULongMax=StringFormat("%I64u",ULONG_MAX);
    string DateTimeMax=StringFormat("%I64u",DateMax);

    As a result of this code, a message box with the variable values will open.

    The format for floating-point numbers is indicated by the symbol "f":

    double Percents=5.5;
    //--- veshchestvennoe chislo v vide stroki
    string str=StringFormat("Percents = %f",Percents);
    Print(str);

    After executing this code, the string "Percents = 5.500000" will be stored in the str variable; by default, six digits after the decimal point are output. You can specify the required number of digits:

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

    To do this, a dot is placed, indicating the decimal separator, and the number of digits after it, in this example 2 digits. In this case, the string "Percents = 5.50" will be stored in the str variable. This formatting option exactly replaces the DoubleToString() function.

    You can specify the total length of the number: to do this, immediately after the "%" sign, put "0" and the number that defines the length of the number, then specify the number of digits after the decimal point (if needed):

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

    A total length of 6 characters is specified, of which one character will be occupied by the decimal separator and two more by the digits after the decimal point. Therefore, the string "Percents = 005.50" will be stored in the str variable.

    If the message needs to display the percent sign "%", and it is used to indicate value insertion positions, you need to write it twice in a row "%%":

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

    In this case, the str variable will contain the string "Percents = 005.50%".

    You can also define the length of the number when outputting integer variables:

    int Variable=123;
    //--- tseloe chislo v vide stroki s zadannoy dlinoy vyvoda
    string str=StringFormat("Variable = %05i",Variable);
    Print(str);

    After executing this code, the string "Variable = 00123" will be stored in the str variable.

    If a smaller number of digits is specified than the number contains, it will still be output correctly:

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

    In this case, the str variable will contain the string "Variable = 123", that is, a 3-digit number is output, despite the fact that the specified length is 2.

    Real numbers can be output in scientific format (a mantissa with six digits after the decimal separator and an exponent); the symbol "e" is used for this:

    double Variable=123.456;
    //--- veshchestvennoe chislo v vide stroki v nauchnoy forme
    string str=StringFormat("Variable = %e",Variable);
    Print(str);

    After this code runs, the string "1.234560e+002" will be stored in the variable str. You can use an uppercase "E" as well; it works the same as a lowercase "e", except that the formatted string will contain an uppercase "E" instead of a lowercase "e".

    There is another option for formatting real numbers: "g". In this case, only six digits are output (not counting the decimal separator). If the length of the integer part of the number exceeds six digits, the number is output in scientific form:

    double Variable1=12.3456789;
    double Variable2=1234567.89;
    //--- poluchenie veshchestvennykh chisel v vide strok s ispolzovaniem "g"
    string str1=StringFormat("Variable = %g",Variable1);
    string str2=StringFormat("Variable = %g",Variable2);
    Print(str1+" "+str2);

    In this example, the string " 12.3457" will be stored in the variable str1, and the string "1.23457e+006" in the variable str2. When using an uppercase "G", everything will work exactly the same, except that an uppercase "E" will be output instead of a lowercase "e".

    Messages in Different Languages

    The StringFormat() function makes it possible to give a program a very useful capability: displaying messages in different languages depending on the interface language set in the terminal.

    You can find out which interface language is selected by calling the TerminalInfoString() function with the TERMINAL_LANGUAGE identifier. When the program starts, we prepare a formatting string depending on the interface language and then use it in the program. A sample expert with this capability is shown below:

    //--- peremennaya dlya formatiruyushchey stroki
    string FormatString;
    //+------------------------------------------------------------------+
    //| Obrabotka sobytiya Init                                           |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- poluchenie formatiruyushchey stroki
       FormatString=GetFormatString();
    //--- dopolnitelnyy vyzov, na sluchay, chtoby v vykhodnye ekspert otrabotal khotya by odin raz
       OnTick();
       return(0);
      }
    //+------------------------------------------------------------------+
    //| Obrabotka sobytiya Tick                                           |
    //+------------------------------------------------------------------+
    void OnTick()
      {
       int Variable1,Variable2,Variable3;
       Variable1=MathRand()%10;        // Sluchaynoe chislo ot 0 do 10
       Variable2=MathRand()%10;        // Eshche odno sluchaynoe chislo
       Variable3=Variable1+Variable2; // Summa chisel
    //--- vyvod rezultata
       Alert(StringFormat(FormatString,Variable1,Variable2,Variable3));
      }
    //+------------------------------------------------------------------+
    //| Opredelenie formatiruyushchey stroki                                 |
    //+------------------------------------------------------------------+
    string GetFormatString(void)
      {
       string Language=TerminalInfoString(TERMINAL_LANGUAGE);
    //--- proverka yazykov
       if(Language=="Russian") return("%i plyus %i ravno %i");     // russkiy
       if(Language=="Spanish") return("%i más %i es igual a %i"); // ispanskiy
    //--- Dlya vsekh ostalnykh sluchaev - angliyskiy
       return("%i plus %i equals %i");
      }

    The expert adds two random numbers and outputs a text message about its actions, for example, "1 plus 2 equals 3".

    With this, we have finished considering everything related to string output. Now let us move on to slightly more complex manipulations with strings.

    Basic String Functions

    If a string is entered through the program properties window or read from a file, it may contain extra spaces. They may appear either because of a user's accidental carelessness or perhaps because it was more convenient for them. Before performing any operations on a string, it is advisable to remove spaces from its edges. For this, the MQL5 language provides the functions StringTrimLeft() (removes spaces on the left) and StringTrimRight() (removes spaces on the right). These functions remove not only spaces, but also tab and newline characters. When working with strings, it is often necessary to remove spaces from both sides at once, so it will be useful to write a function that does this:

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

    StringTrimLeft removes carriage return characters, spaces, and tab characters from the beginning of the string up to the first significant character. The string is modified in place. StringTrimRight removes carriage return characters, spaces, and tab characters from the last significant character to the end of the string. StringReplace replaces all found substrings in the string with the specified sequence of characters.

    The StringFind() function is used to search for a substring and returns the index of the first occurrence of the substring in the string. The first parameter passed to the function is the string in which the search is performed, the second parameter defines the substring being searched for, and the third (optional) parameter can define the position from which the search begins. If the third parameter is not specified, the function works as if its value were 0, that is, the search is performed from the very beginning of the string. Let us find the position of the substring "5" in the string "Programming for MQL5 for MetaTrader 5":

    string str="Programmirovanie na MQL5 dlya MetaTrader 5";
    //--- poluchenie pozitsii simvola
    int Pos=StringFind(str,"5");
    //--- vyvod rezultata
    Print(IntegerToString(Pos));

    After this code runs, the value 23 will be stored in the variable Pos. In total, the substring "5" occurs twice, but the function returned only the position of the first occurrence. If you count the position just by looking at the string, you get 24. The fact is that the function counts starting from zero, not one. If the desired substring is absent from the string, the function returns -1.

    The StringSubstr() function is used to extract a substring from a specified position with a specified length. Let us extract a substring from position 23 with length 1:

    string str="Programmirovanie na MQL5 dlya MetaTrader 5";
    //--- poluchenie podstroki s ukazannoy pozitsii i dlinoy
    string str2=StringSubstr(str,23,1);
    Print(str2);

    Now that we have understood the basic functions, let us use them to write a useful function for removing a specified list of characters from a string. The function receives the original string and a string representing the list of characters that need to be removed from the original one.

    string TrimL(string Str,string List="\t\n ;")
      {
    //--- peremennaya dlya odnoy bukvy stroki Str
       string ch;
       int Len=StringLen(Str);
       int i=0;
    //--- tsikl po vsem bukvam stroki Str
       for(;i<Len;i++)
         {
          //--- ocherednaya bukva stroki Str
          ch=StringSubstr(Str,i,1);
          //--- esli etoy bukvy net v spiske List, znachit stroka dolzhna nachinatsya s etoy pozitsii 
          if(StringFind(List,ch,0)==-1)
            {
             break; // zavershaem rabotu tsikla
            }
         }
    //--- izvlekaem podstroku i vozvrashchaem ee
       return(StringSubstr(Str,i));
      }

    An uppercase and a lowercase letter, for example, "A" and "a", do not differ in meaning for a human, but for a computer they are two completely different characters. If, when requesting market data using the SymbolInfoDouble() function, you specify the symbol "eurusd" instead of, for example, "EURUSD", the function will not return the value we need. When entering a symbol through the properties window, such an error is very likely. To change case, the MQL5 language provides the functions StringToLower() (convert to lowercase) and StringToUpper() (convert to uppercase).

    StringToLower converts all characters of the specified string to lowercase in place:

    bool StringToLower(
    string& string_var // stroka dlya obrabotki
    );

    StringToUpper converts all characters of the specified string to uppercase in place:

    bool StringToUpper(
    string& string_var // stroka dlya obrabotki
    );

    That is all, goodbye everyone!

    Respectfully, Dmitry aka Silentspec
    Tlap.io

    Working with strings in MQL5, a video lesson. The main functions for working with strings, string concatenation, formatting strings by template, special characters, and so on.