C#distance(英里/公里/等)字符串解析库

时间:2010-11-10 00:08:53

标签: c# parsing distance

有没有任何C#库提供与谷歌在输入查询时所做的相同功能,例如“13英里743码(米)”,它将返回“21 600米”(例如)。

我想要做的是给函数字符串部分13 miles 743 yards,然后以米为单位向后吐出一个int / double。它需要能够处理所有单位输入类型(公里/米/弗隆/英里/码/ ...),但输出只需要以米为单位。

编写自己的文件并不难,但只要有一个经过测试的库就可以了。

3 个答案:

答案 0 :(得分:3)

我找不到任何答案,所以我建立了自己的:)这里唯一真正的“魔法”是Regex表达式,用于从原始字符串中获取值/单位组。从那里,它是简单的分数/数字解析,然后计算每个单位代表多少米。我没有测试过这么多,所以如果你发现了改进或错误,请告诉我(下面的代码在无法处理的情况下应该抛出异常)。

它不会处理愚蠢的用户输入,但是如果每个部分的格式为“[number] [unit]”,我认为它应该可以正常工作。如果输入不符合(例如,12/32/431.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 :(得分:1)

执行此操作的一种方法是向Google发出请求,然后解析返回的html。

更新:这将是非常低效的,但他们已经为您完成了艰苦的工作。为了使这项工作,您必须使用英语(为您的示例)语言解析器来获取输入,去除无意义的单词/符号(如和逗号),找到值(13和743),找到单位(英里,码和米),找到操作员(在或到)。在那之后,你必须确保它具有语法意义。您还必须保留转换表(并不难)。

这绝对是可能的,但这是一堆工作,而且我不确定是否已存在(除谷歌之外)。你需要担心的角落案例很多。让图书馆完成工作将是一项有趣的练习,但很难捕捉所有案例。

更简单的解决方案是给他们分离控件以解析语言

答案 2 :(得分:0)

这是一个单位转换库。没有所有你想要的测量单位(弗隆!?),但看起来最多:

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

没有找到任何字符串解析。老实说,这似乎是一种容易出错的输入方式。考虑:

  • 13英里 743码(米)
  • 13英里743码
  • 13英里 743码

所有意思都是一样的,即使你给出了关于如何写出字符串的具体指示,他们也可能会对他们做出有意义的事情......

如果你想了解人们正在尝试说什么,那么你真的可能会更好地与谷歌合作。否则,您可能会尝试使用特定输入。