2010-11-10 73 views
5

是否有任何C#庫在那裏提供相同類型的功能谷歌當你鍵入查詢如「13英里743碼米」它會返回「21 600米」(例如)。C#距離(英里/公里/英寸)字符串解析庫

我想要做的是給函數字符串部分13 miles 743 yards,它吐出一個以米爲單位給定距離的int/double。它需要能夠處理所有的單位輸入類型(公里/米/弗朗/英里/碼/ ...),但輸出只能以米爲單位。

編寫我自己的代碼並不難,但只要有一個測試過的庫準備好就可以了。

回答

3

我找不到任何答案,所以我建立了自己的:)這裏唯一真正的「魔術」是從原始字符串中獲取值/單位組的正則表達式。從那裏它是簡單的分數/數字解析,然後計算出每個單位代表多少米。我還沒有測試過這麼多,所以請讓我知道,如果你發現改進或錯誤(下面的代碼應該拋出一個異常,當它無法處理的情況下)。

它不會處理愚蠢的用戶輸入,但提供每個部分的格式是「[數字] [單位]」我認爲它應該工作正常。無論如何,如果輸入不符合(例如,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樣式格式

+0

只需注意,我只是在過去一小時內完成了編碼。我將在接下來的日子裏對它進行更徹底的測試,但是如果其他人發現我沒有發現的錯誤,我們會在這裏進行測試。如果發現任何錯誤,我會更新這個答案。 – mike 2010-11-11 08:44:16

1

做到這一點的一種方法是向谷歌提出請求,然後解析返回的HTML。

更新:這將是非常低效,但他們已經照顧到你的辛勤工作。爲了使這個工作,你必須使英語(爲你的例子)語言分析器接受輸入,去掉無意義的單詞/符號(如和逗號),找到值(13和743),找到單位(英里,碼和米)找到操作員(進入或到)。之後,您必須確保它具有語法意義。你還必須保留一個轉換表(不難)。

這絕對有可能,但它是一堆工作,我不確定是否已經存在(除谷歌以外)。有太多的角落案例你必須擔心。讓圖書館做這項工作將是一件有趣的工作,但很難抓住所有案例。

的更容易的解決辦法是給他們離散的控制採取語言解析出

+0

是...很聰明.. – 2010-11-10 00:23:16

+0

我不會說我想分析每次調用一個在線服務的距離'聰明'。特別是如果你想離線解析距離,這是完全合理的。 – mike 2010-11-10 00:32:51

+0

好吧,這不是真的很聰明,但它的工作原理。他們已經關注語言解析 – 2010-11-10 01:15:09

0

這裏是一個單位轉換庫。沒有所有的測量(弗隆!?)你想要的單位,但看起來有最:

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

沒有找到與字符串解析什麼。老實說,這似乎是一個容易出錯的方式來獲得輸入。試想一下:

  • 13英里743碼米
  • 13英里743碼
  • 13英里743碼

所有意味着同樣的事情,即使你給出了關於如何寫作的痛苦具體指示e出他們的字符串,他們可能會做他們對他們有意義的東西...

如果你想進入什麼人試圖說,那麼你真的可能會更好地與谷歌去。否則,你可能會嘗試填入特定的輸入。

+0

我認爲你是過度複雜的問題。輸出只能是米,所以字符串的「米」或「米」部分不存在。剝離「和」絨毛自然也是如此。我沒有選擇輸入,我只是需要將這些半井形成的字符串解析成距離。如果我有選擇,我不會問這個問題:)而解決問題的每種方法都會有錯誤,只有這麼多才能做到。如果字符串格式不正確,那只是運氣不好,解析會失敗。 – mike 2010-11-11 08:35:06

相關問題