2010-11-10 10 views
5

¿Hay # bibliotecas de C por ahí que proporcionan el mismo tipo de Google funcionalidad lo hace cuando se escribe en una consulta como "13 millas 743 yardas en metros" lo hará devolver "21 600 metros" (por ejemplo).C# distancia (millas/km/etc.) Procesamiento de cadenas biblioteca

Lo que quiero poder hacer es darle una función a la parte de cadena 13 miles 743 yards y escupe un int/doble con la distancia dada en metros. Necesita poder manejar todos los tipos de entrada de la unidad (kilómetros/metros/estadios/millas/yardas/...) pero la salida solo tiene que estar en metros.

No es tan difícil de escribir mi propio, pero sería genial para tener una biblioteca probado listo para funcionar.

Respuesta

3

no pude encontrar ninguna respuesta a esto, así que construyeron mi propia :) La única 'magia' real aquí es la expresión expresiones regulares para agarrar los grupos de valores/unidades de la cadena original. A partir de ahí, se realiza un análisis simple de fracciones/números y luego se calcula cuántos metros representa cada unidad.No he probado nada en absoluto, así que avíseme si encuentra mejoras o errores (el siguiente código debe arrojar una excepción cuando no puede manejar una situación).

No manejará la entrada del usuario estúpido, pero siempre que el formato de cada sección sea "[number] [unit]" Creo que debería funcionar bien. No hay mucho que pueda asumir si la entrada no se ajusta (por ejemplo, 12/32/43 o 1.43.3.2.44 como valor) de todos modos. Creo que también manejará la pelusa extra en la oración como 1 kilometer and 10 miles (quitará el and). No he agregado todas las unidades posibles, si conoce una lista completa de unidades & existe un equivalente en metros que me encantaría saber al respecto.

Aquí hay un par de pruebas,

var a = ExtractDistance("1 1/16 Miles 3/4 yards"); 
var b = ExtractDistance("02234890234.853 meters"); 
var c = ExtractDistance("1.8 miles 3.2 furlong"); 
var d = ExtractDistance("1 kilometer"); 
var e = ExtractDistance("1/16 Miles"); 

y aquí está mi código:

private static Dictionary<string, double> _DistanceLookup = new Dictionary<string, double>() 
{ 
    {"mile", 1609.344}, 
    {"furlong", 201.168}, 
    {"yard", 0.9144}, 
    {"inch", 0.0254}, 
    {"foot", 0.3048}, 
    {"feet", 0.3048}, 
    {"kilometer", 1000}, 
    {"kilometre", 1000}, 
    {"metre", 1}, 
    {"meter", 1}, 
    {"centimeter", 0.01}, 
    {"centimetre", 0.01}, 
    {"millimeter", 0.001}, 
    {"millimetre", 0.001}, 
}; 

private static double ConvertFraction(string fraction) 
{ 
    double value = 0; 
    if (fraction.Contains('/')) 
    { 
    // If the value contains /, we need to work out the fraction 
    string[] splitVal = fraction.Split('/'); 
    if (splitVal.Length != 2) 
    { 
     ScrewUp(fraction, "splitVal.Length"); 
    } 

    // Turn the fraction into decimal 
    value = double.Parse(splitVal[0])/double.Parse(splitVal[1]); 
    } 
    else 
    { 
    // Otherwise it's a simple parse 
    value = double.Parse(fraction); 
    } 
    return value; 
} 

public static double ExtractDistance(string distAsString) 
{ 
    double distanceInMeters = 0; 
    /* This will have a match per unit type. 
    * e.g., the string "1 1/16 Miles 3/4 Yards" would have 2 matches 
    * being "1 1/16 Miles", "3/4 Yards". Each match will then have 4 
    * groups in total, with group 3 being the raw value and 4 being the 
    * raw unit 
    */ 
    var matches = Regex.Matches(distAsString, @"(([\d]+[\d\s\.,/]*)\s([A-Za-z]+[^\s\d]))"); 
    foreach (Match match in matches) 
    { 
    // If groups != 4 something went wrong, we need to rethink our regex 
    if (match.Groups.Count != 4) 
    { 
     ScrewUp(distAsString, "match.Groups.Count"); 
    } 
    string valueRaw = match.Groups[2].Value; 
    string unitRaw = match.Groups[3].Value; 

    // Firstly get the value 
    double value = 0; 
    if (valueRaw.Contains(' ')) 
    { 
     // If the value contains /, we need to work out the fraction 
     string[] splitVal = valueRaw.Split(' '); 
     if (splitVal.Length != 2) 
     { 
     ScrewUp(distAsString, "splitVal.Length"); 
     } 

     // Turn the fraction into decimal 
     value = ConvertFraction(splitVal[0]) + ConvertFraction(splitVal[1]); 
    } 
    else 
    { 
     value = ConvertFraction(valueRaw); 
    } 

    // Now work out based on the unit type 
    // Clean up the raw unit string 
    unitRaw = unitRaw.ToLower().Trim().TrimEnd('s'); 

    if (!_DistanceLookup.ContainsKey(unitRaw)) 
    { 
     ScrewUp(distAsString, "unitRaw"); 
    } 
    distanceInMeters += value * _DistanceLookup[unitRaw]; 
    } 
    return distanceInMeters; 
} 

private static void ScrewUp(string val, string prop) 
{ 
    throw new ArgumentException("Extract distance screwed up on string [" + val + "] (bad " + prop + ")"); 
} 

Enjoy! Espero que alguien encuentre esto útil. Por favor deja comentarios/sugerencias.

EDITAR: se ha añadido un , a la expresión regular para manejar formato 1,300 meters estilo

+0

Solo para observar, acabo de terminar de codificar esto en la última hora. Voy a probarlo más a fondo en los próximos días, pero ya lo puse aquí por si otros detectan errores que yo no veo. Actualizaré esta respuesta si se encuentran errores. – mike

1

Una forma de hacerlo es hacer una solicitud a Google a continuación, analizar el HTML devuelto.

Actualización: Esto será realmente ineficiente, pero se han encargado del duro trabajo para usted. Para que esto funcione, debe hacer un analizador de lenguaje inglés (para su ejemplo) para tomar la entrada, quitar las palabras/símbolos sin sentido (como y y comas), encontrar los valores (13 y 743), encontrar las unidades (millas, yardas y metros), encuentre los operadores (en o para). Después de eso, debes asegurarte de que tenga sentido sintáctico. También debe mantener una tabla de conversiones (no difícil).

Es definitivamente posible, pero es un montón de trabajo, y no estoy seguro de si ya existe (que no sea Google). Hay tantos casos de esquina que debes preocuparte. Hacer una biblioteca para hacer el trabajo sería un ejercicio divertido, pero es difícil detectar todos los casos.

La solución más fácil sería que les dan los controles discretos para tomar el análisis sintáctico del lenguaje a cabo

+0

sí ... muy inteligente .. –

+0

Yo no diría que llamar a un servicio en línea cada vez que quiero analizar es una distancia 'inteligente'. Especialmente si quiere analizar la distancia fuera de línea, lo cual es totalmente razonable. – mike

+0

Ok, no es realmente "inteligente" pero funciona. Ya se han ocupado del análisis sintáctico del lenguaje –

0

Aquí es una biblioteca de conversión de unidades. No tiene todas sus unidades de medida deseada (estadios !?), pero parece tener más:

http://www.codeproject.com/KB/library/Measurement_Conversion.aspx

no he encontrado nada con el análisis de cadenas. Honestamente, parece una forma propensa a errores para obtener información. Considere:

  • 13 millas y 743 yardas en metros
  • 13 millas 743 yardas a metros
  • 13 millas y 743 yardas a metros

Todos significa lo mismo e incluso si le da instrucciones dolorosamente específicas sobre cómo escribir e cabo su cadena que probablemente harán lo que tiene sentido para ellos ...

Si quieres entrar en lo que la gente está tratando de decir, entonces realmente podría ser mejor ir con Google. De lo contrario, puede tratar de seleccionar las entradas específicas.

+0

Creo que está complicando demasiado mi pregunta. La salida solo tiene que ser metros, por lo que la parte 'a metros' o' en metros' de la cuerda no existe. Excluir la pelusa 'y' también se hace naturalmente. No tengo otra opción para la entrada, solo estoy obligado a analizar estas cuerdas semi-bien formadas en distancias. Si tuviera una opción, no haría la pregunta :) Y cada método para resolver el problema tendrá errores, solo hay mucho que puedes hacer. Si la cadena está en mal formato, es mala suerte y el análisis fracasará. – mike

Cuestiones relacionadas