Comparación de cadenas
Para comparar cadenas en MQL5, puede utilizar los operadores de comparación estándar, en particular '==', '!=', '>', '<'. Todos estos operadores realizan comparaciones carácter por carácter, distinguiendo entre mayúsculas y minúsculas.
Cada carácter tiene un código Unicode que es un entero del tipo ushort. En consecuencia, primero se comparan los códigos de los primeros caracteres de dos cadenas, luego los códigos de los segundos, y así sucesivamente hasta que se alcanza la primera falta de coincidencia o el final de una de las cadenas.
Por ejemplo, la cadena «ABC» es menor que «abc», ya que los códigos de las letras mayúsculas en la tabla de caracteres son menores que los códigos de las letras minúsculas correspondientes (en el primer carácter ya obtenemos que «A» < «a»). Si las cadenas tienen caracteres coincidentes al principio, pero una de ellas es más larga que la otra, se considera que la cadena más larga es mayor («ABCD» > «ABC»).
Estas relaciones entre cadenas forman el orden lexicográfico. Cuando la cadena «A» es menor que la cadena «B» («A» < «B»), se dice que «A» precede a «B».
Para familiarizarse con los códigos de caracteres, puede utilizar la aplicación estándar de Windows «Tabla de caracteres». En ella, los caracteres están dispuestos en orden de códigos crecientes. Además de la tabla general de Unicode, que incluye muchas lenguas nacionales, existen páginas de códigos: las tablas estándar ANSI con códigos de caracteres de un byte, difieren para cada lengua o grupo de lenguas. Analizaremos esta cuestión con más detalle en la sección Trabajar con símbolos y páginas de códigos.
La parte inicial de las tablas de caracteres con códigos de 0 a 127 es la misma para todas las lenguas. Esta parte se muestra en la siguiente tabla.

Tabla de códigos de caracteres ASCII
Para obtener el código del carácter, tome el dígito hexadecimal de la izquierda (el número de línea en el que se encuentra el carácter) y sume el número de arriba (el número de columna en el que se encuentra el carácter): el resultado es un número hexadecimal. Por ejemplo, para '!' hay 2 a la izquierda y 1 arriba, lo que significa que el código del carácter es 0x21, o 33 en decimal.
Los códigos hasta 32 son códigos de control. Entre ellos se encuentran, en particular, la tabulación (código 0x9), el avance de línea (código 0xA) y el retorno de carro (código 0xD).
En los archivos de texto de Windows se utiliza un par de caracteres 0xD 0xA seguidos para saltar a una nueva línea. Nos hemos familiarizado con los literales de MQL5 correspondientes en la sección Tipos de caracteres. 0xA puede denotarse como '\n' y 0xD como '\r'. La tabulación 0x9 también tiene su propia representación: '\t'.
La API de MQL5 proporciona la función StringCompare, que permite desactivar la distinción entre mayúsculas y minúsculas al comparar cadenas.
int StringCompare(const string &string1, const string &string2, const bool case_sensitive = true)
La función compara dos cadenas y devuelve uno de tres valores: +1 si la primera cadena es «mayor que» la segunda; 0 si las cadenas son «iguales»; -1 si la primera cadena es «menor que» la segunda. Los conceptos «mayor que», «menor que» e «igual a» dependen del parámetro case_sensitive .
Cuando el parámetro case_sensitive es igual a true (que es el valor predeterminado), la comparación distingue entre mayúsculas y minúsculas, considerándose las mayúsculas mayores que las minúsculas similares. Es el orden inverso al orden lexicográfico estándar según los códigos de caracteres.
Cuando se distingue entre mayúsculas y minúsculas, la función StringCompare utiliza un orden de mayúsculas y minúsculas diferente del orden lexicográfico. Por ejemplo, sabemos que la relación «A» < «a» es verdadera, en la que el operador '<' se guía por códigos de caracteres. Por lo tanto, las palabras en mayúscula deben aparecer en el diccionario hipotético (array) antes de las palabras con la misma letra minúscula. No obstante, al comparar «A» y «a» utilizando la función StringCompare("A", "a"), obtenemos +1, lo que significa que «A» es mayor que «a». Así, en el diccionario ordenado, las palabras que empiecen por minúscula irán primero, y sólo después vendrán las palabras con mayúscula.
En otras palabras: la función ordena las cadenas alfabéticamente. Además, en el modo de distinción entre mayúsculas y minúsculas, se aplica una regla adicional: si hay cadenas que sólo difieren en mayúsculas o minúsculas, las que tienen letras mayúsculas siguen a sus homólogas con letras minúsculas (en las mismas posiciones de la palabra).
Si el parámetro case_sensitive es igual a false, las letras no distinguen entre mayúsculas de minúsculas, por lo que las cadenas «A» y «a» se consideran iguales, y la función devuelve 0.
Puede comprobar diferentes resultados de comparación mediante la función StringCompare y con el operador utilizando el script StringCompare.mq5.
void OnStart()
|
En la sección Plantillas de funciones hemos creado un algoritmo de ordenación rápida. Vamos a transformarlo en una clase de plantilla y a utilizarlo para varias opciones de ordenación: utilizando operadores de comparación, así como la función StringCompare con y sin la distinción de mayúsculas y minúsculas activada. Pongamos la nueva clase QuickSortT en el archivo de encabezado QuickSortT.mqh y conectémosla al script de prueba StringCompare.mq5.
La API de clasificación se ha mantenido prácticamente sin cambios.
template<typename T>
|
La principal diferencia es que hemos añadido un método virtual Compare, que por defecto contiene una comparación utilizando los operadores '>' y '<', y devuelve +1, -1, o 0 de la misma forma que StringCompare. El método Compare se utiliza ahora en el método QuickSort en lugar de una simple comparación y debe sobrescribirse en las clases hijas para poder utilizar la función StringCompare o cualquier otra forma de comparación.
En concreto, en el archivo StringCompare.mq5, implementamos la siguiente clase «comparador» derivada de QuickSortT<string>:
class SortingStringCompare : public QuickSortT<string>
|
El constructor recibe 1 parámetro, que especifica el signo de comparación de la cadena teniendo en cuenta (true) o ignorando (false) el registro. La comparación de cadenas en sí se realiza en el método virtual redefinido Compare que llama a la función StringCompare con los argumentos y la configuración dados.
Para probar la ordenación, necesitamos un conjunto de cadenas que combine mayúsculas y minúsculas. Podemos generarlo nosotros mismos: basta con desarrollar una clase que realice permutaciones (con repetición) de caracteres de un conjunto predefinido (alfabeto) para una longitud de conjunto dada (cadena). Por ejemplo, puede limitarse al pequeño alfabeto «abcABC», es decir, tres letras inglesas de puño y letra en ambos casos, y generar a partir de ellas todas las cadenas posibles de 2 caracteres.
La clase PermutationGenerator se suministra en el archivo PermutationGenerator.mqh y se deja para estudio independiente. Aquí sólo presentamos su interfaz pública.
class PermutationGenerator
|
Al crear un objeto generador, debe especificar la longitud de los conjuntos generados length (en nuestro caso, será la longitud de las cadenas, es decir, 2) y el número de elementos diferentes de los que se compondrán los conjuntos (en nuestro caso, es el número de letras únicas, es decir, 6). Con estos datos de entrada, deberían obtenerse 6 * 6 = 36 variantes de líneas.
El proceso en sí se lleva a cabo con el método run. Se utiliza una clase de plantilla para devolver un array con los resultados SimpleArray, de lo que hablamos en la sección Plantillas de métodos. En este caso, se parametriza mediante el tipo de estructura result.
La llamada del generador y la creación real de cadenas de acuerdo con el array de permutaciones recibido de él (en forma de índices de letras en cada posición para todas las cadenas posibles) se realiza en la función auxiliar GenerateStringList.
void GenerateStringList(const string symbols, const int len, string &result[])
|
Aquí utilizamos varias funciones que todavía nos son desconocidas (ArrayResize, ShortToString), pero llegaremos a ellas pronto. Por ahora, sólo debemos saber que la función ShortToString devuelve una cadena formada por ese único carácter basado en el código de caracteres de tipo ushort. Utilizando el operador '+=' concatenamos cada cadena resultante de dichas cadenas de un solo carácter. Recuerde que el operador [] está definido para cadenas, por lo que la expresión symbols[k] devolverá el k-ésimo carácter de la cadena symbols. Por supuesto, k puede ser a su vez una expresión entera, y aquí r[i].indices[j] se refiere al i-ésimo elemento del array r del que se lee el índice del carácter «alfabeto» para la j-ésima posición de la cadena.
Cada cadena recibida se almacena en un array de parámetros result.
Vamos a aplicar esta información en la función OnStart.
void OnStart()
|
El script primero obtiene todas las opciones de cadena en el array de mensajes y luego las ordena en tres modos: usando los operadores de comparación integrados, usando la función StringCompare en el modo que no distingue entre mayúsculas y minúsculas, y usando la misma función en el modo que sí distingue entre mayúsculas y minúsculas.
Obtendremos la siguiente salida de registro:
Original data[36]:
|
La salida muestra las diferencias en estos tres modos.