2012-07-08 16 views
5

Parece una pregunta muy simple, pero sorprendentemente hay muy poco escrito sobre ella en Internet, y estoy teniendo dificultades para implementarla correctamente por mi cuenta. ¿Cuál es la mejor manera de implementar una función de comparación modular en caracteres ASCII en Java, de modo que la comparación "envuelva" el final del alfabeto? Quiero usarlo para una función "entre" que puede dividir todo el alfabeto en ubicaciones arbitrarias, y devolver correctamente "verdadero" cuando se le pregunte si 'y' está entre 'x' y 'b'.Comparación modular de caracteres

ya he encontrado todas las preguntas y respuestas que hablan de modular la aritmética en los personajes, así que saben cómo hacer además modular (carácter cambiante) con el código de la siguiente manera:

char shifted = (((original - 'a') + 1) % 26) + 'a'; 

Sin embargo, esto se basa en las funciones aritméticas modulares integradas de Java, que no tienen equivalente para comparar. Incluso si estaba usando enteros simples, no tengo forma de preguntarle a Java si es < b < c mod 26 (que debería volver verdadero si a = 24, b = 25 y c = 1).

Así que la pregunta general es, ¿cuál es la mejor manera de implementar las operaciones de comparación en Java? Si ese es un problema demasiado difícil, ¿existe al menos una forma de hacer que esas comparaciones funcionen para el alfabeto ASCII?

+0

Tenga en cuenta que la "comparación modular" no tiene sentido para una comparación binaria: no hay un orden "menor que" en la aritmética modular. Sin embargo, una cosa "entre" todavía es posible, por lo que su pregunta es válida. – MvG

Respuesta

2

En la prueba de A < B < C en una cola circular, siempre puede suponer A <= B y se ha ajustado o no.

Si A < B, no se ha realizado ningún ajuste. Si cualquiera de los B < C or C < A, entonces B está entre A y C.

Si A > B, entonces ha envuelto. Si B < C and C < A, entonces B está entre A y C.

Deberá definir usted mismo cómo manejar A == B, B == C o A == C.

+0

Esto es brillantemente simple. La mejor parte es que no depende de la longitud del alfabeto, así que puedo usar la misma función incluso si mi cadena podría contener signos de puntuación o caracteres Unicode sin tener que cambiar el número mágico 26. – Edward

+0

También funcionaría bien para alfabetos con valores que son comparables, pero no necesariamente contiguos de extremo a extremo, como hexadecimal o base64. – phatfingers

1

Así que su pregunta es: ¿es el carácter c_1 entre los caracteres c_2 y c_3, siempre que el alfabeto se ajuste?

  • convertir cada carácter a un número (es decir, a = 1, b = 2, ..., z = 26). En su ejemplo, eso sería c_1 = 'y' = 25 entre c_2 = 'x' = 24 y c_3 = 'b' = 2).
  • Si c_3 < c_2, agregue 26 a c_3. En su ejemplo, ese es el caso porque 2 < 24.
  • Ahora tenemos c_1 = 25, c_2 = 24 y c_3 = 28.
  • Compruebe si c_1 >= c_2 && c_1 <= c_3 tiene. Si lo hace, entonces el personaje está entre los dos límites. Si no se mantiene, continúe con el siguiente paso.
  • Agregue 26 a c_1 y compruebe si este valor cumple con la comprobación anterior. Si lo hace, entonces el personaje está dentro de los límites envueltos. Si no lo hace, entonces pare.

En este enfoque, básicamente está agregando 26 al 'segundo' alfabeto. Por lo tanto:

... 23 24 25 26 1 2 3 4 

se convierte en:

... 23 24 25 26 27 28 29 30 

A continuación, puede hacer operaciones aritméticas como se haría normalmente.

Editar: Algoritmo actualizado basado en el comentario de MvG. De hecho, hay situaciones múltiples: "¿hay 25 entre 24 y 2?" pero también "¿es 1 entre 24 y 2?". En este último caso, también necesita verificar si (1 + 26) está entre 24 y (2 + 26) - y esto se cumple, por lo que el carácter 'a' está realmente entre 'x' y 'b'.

+0

También debe agregar 26 a 'c_1' y ver si eso está dentro del rango. – MvG

+0

@MvG: Gracias, he actualizado la respuesta con más información. –

0

Dependiendo de sus gustos, puede utilizar operadores de módulo en lugar de sentencias if. Para realizar la comparación en una sola línea, hacer algo como esto:

public static boolean isStrictlyBetween(char a, char x, char b) { 
    // assuming x, a, and b are all the same case (lower or upper). 
    return ((x - a + 26) % 26) < ((b - a + 26) % 26); 
} 

Este código dice que devolverá true si la distancia hacia la derecha desde la A a la x es menor que la distancia hacia la derecha desde a hasta b. El +26 asegura que el resultado de la expresión de diferencia es positivo (el% de números negativos tiene un extraño funcionamiento en algunos idiomas). El% 26 realiza su módulo deseado.

Cuestiones relacionadas