C # расстояние (миля / км / и т. - PullRequest
5 голосов
/ 10 ноября 2010

Существуют ли какие-либо библиотеки C #, которые предоставляют те же функции, что и Google, когда вы вводите запрос, например, "13 миль 743 ярдов в метрах", он возвращает "21 600 метров" (например).

Что я хочу сделать, так это дать функции строковую часть 13 miles 743 yards, и она выдает int / double с заданным расстоянием в метрах. Он должен быть в состоянии обрабатывать все типы ввода единиц (километры / метры / фарлонги / мили / ярды / ...), но вывод должен быть только в метрах.

Не так сложно написать свою собственную, но было бы здорово просто иметь протестированную библиотеку, готовую к работе.

Ответы [ 3 ]

3 голосов
/ 11 ноября 2010

Я не смог найти никакого ответа на этот вопрос, поэтому я построил свой собственный :) Единственное настоящее «волшебство» здесь - это выражение Regex для извлечения групп значений / единиц из исходной строки. Отсюда происходит простой анализ дроби / числа, а затем определение количества метров, которое представляет каждая единица. Я совсем не тестировал это, поэтому, пожалуйста, дайте мне знать, если вы найдете улучшения или ошибки (приведенный ниже код должен вызывать исключение, когда он не может обработать ситуацию).

Он не будет обрабатывать глупый пользовательский ввод, но при условии, что формат каждого раздела - "[число] [единица]" Я думаю, что он должен работать нормально. Вы не можете предположить, что входные данные не соответствуют (например, 12/32/43 или 1.43.3.2.44 как значение) в любом случае. Я думаю, что он будет обрабатывать дополнительный пух в предложении, например, 1 kilometer and 10 miles (исключит and). Я не добавил каждую возможную единицу, если вы знаете полный список единиц и эквивалентный метр, я хотел бы знать об этом.

Вот пара тестов,

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");

и вот мой код:

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 + ")");
}

Наслаждайтесь! Я надеюсь, что кто-то найдет это полезным. Пожалуйста, оставляйте комментарии / предложения.

РЕДАКТИРОВАТЬ : добавлено , к строке регулярного выражения для обработки 1,300 meters формата стиля

1 голос
/ 10 ноября 2010

Один из способов сделать это - отправить запрос в Google, а затем проанализировать возвращенный HTML.

Обновление: Это будет действительно неэффективно, но они позаботились о тяжелой работе для вас. Чтобы это работало, вам нужно было бы создать синтаксический анализатор английского языка (для вашего примера) для ввода, вычеркнуть бессмысленные слова / символы (например, и и запятые), найти значения (13 и 743), найдите единицы (мили, ярды и метры), найдите операторов (в или к). После этого вы должны убедиться, что это имеет синтаксический смысл. Вы также должны вести таблицу конверсий (не сложно).

Это определенно возможно, но это куча работы, и я не уверен, что она уже существует (кроме Google). Есть так много угловых случаев, о которых вам нужно беспокоиться. Создание библиотеки для выполнения работы было бы увлекательным занятием, но все случаи трудно отследить.

Более простым решением было бы дать им дискретный контроль для анализа языка

0 голосов
/ 10 ноября 2010

Вот библиотека преобразования единиц измерения.Не имеет всех ваших желаемых единиц измерения (фарлонги !?), но, похоже, имеет большинство:

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

Ничего не найдено при разборе строки.Честно говоря, это похоже на склонный к ошибкам способ получения информации.Рассмотрим:

  • 13 миль и 743 ярдов в метрах
  • 13 миль 743 ярдов до метров
  • 13 миль и 743 ярдов до метров

Все означают одно и то же, и даже если вы дадите мучительно конкретные инструкции о том, как выписать их строку, они, вероятно, сделаютчто для них имеет смысл ...

Если вы хотите понять, что люди ПЫТАЮТСЯ сказать, тогда вам действительно лучше пойти с Google.В противном случае вы можете попробовать ввести конкретные данные.

...