C#距离(英里/公里/等)字符串解析库
有没有任何C#库提供与谷歌相同的功能?当你输入一个查询,比如“13英里743码米”,它将返回“21600米”(例如) 我想做的是给一个函数字符串部分C#距离(英里/公里/等)字符串解析库,c#,parsing,distance,C#,Parsing,Distance,有没有任何C#库提供与谷歌相同的功能?当你输入一个查询,比如“13英里743码米”,它将返回“21600米”(例如) 我想做的是给一个函数字符串部分13英里743码,它以米为单位吐出一个int/double。它需要能够处理所有单位输入类型(公里/米/弗隆/英里/码/…),但输出必须以米为单位 编写自己的库并不难,但只要有一个经过测试的库就好了。一种方法是向谷歌发出请求,然后解析返回的html 更新:这将非常低效,但他们已经为您解决了繁重的工作。要实现这一点,您必须制作一个英语(例如)语言解析器来
13英里743码
,它以米为单位吐出一个int/double。它需要能够处理所有单位输入类型(公里/米/弗隆/英里/码/…),但输出必须以米为单位
编写自己的库并不难,但只要有一个经过测试的库就好了。一种方法是向谷歌发出请求,然后解析返回的html 更新:这将非常低效,但他们已经为您解决了繁重的工作。要实现这一点,您必须制作一个英语(例如)语言解析器来获取输入,去掉无意义的单词/符号(如and和逗号),找到值(13和743),找到单位(英里、码和米),找到运算符(in或To)。在那之后,你必须确保它在句法上有意义。您还必须保留一个转换表(不难) 这当然是可能的,但这是一系列的工作,我不确定是否已经存在(除了谷歌)。有那么多角落的案子你得担心。建立一个图书馆来做这项工作将是一个有趣的练习,但很难抓住所有的案例
更简单的解决方案是为他们提供离散的控件,将语言解析带出这里是一个单元转换库。没有您想要的所有测量单位(弗隆!?),但看起来有最多: 未找到任何与字符串分析有关的内容。老实说,这似乎是一种容易出错的获取输入的方法。考虑:
- 13英里和743码(米)
- 13英里743码到米
- 13英里和743码至 仪表
如果你想了解人们想说的话,那么你最好选择谷歌。否则,您可能会尝试使用特定的输入。我找不到任何答案,因此我构建了自己的:)这里唯一真正的“魔力”是正则表达式,它可以从原始字符串中获取值/单位组。从这里开始,它是简单的分数/数字解析,然后计算出每个单位代表多少米。我根本没有测试过这么多,所以如果您发现改进或bug,请告诉我(下面的代码在无法处理情况时应该抛出异常) 它不会处理愚蠢的用户输入,但如果每个部分的格式是“[数字][单位]”,我认为它应该可以正常工作。如果输入不符合(例如,
12/32/43
或1.43.3.2.44
作为一个值),那么您可以假设的情况不多。我认为它也会处理句子中额外的绒毛,例如1公里和10英里
(将去掉和
)。如果你知道一个完整的单位列表,我还没有尽可能地增加每一个单位&我很想知道
这里有几个测试
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 + ")");
}
private static Dictionary\u distance lookup=new Dictionary()
{
{“英里”,1609.344},
{“furlong”,201.168},
{“码”,0.9144},
{“英寸”,0.0254},
{“英尺”,0.3048},
{“英尺”,0.3048},
{“公里”,1000},
{“公里”,1000},
{“米”,1},
{“米”,1},
{“厘米”,0.01},
{“厘米”,0.01},
{“毫米”,0.001},
{“毫米”,0.001},
};
专用静态双小数(字符串小数)
{
双值=0;
if(分数.Contains('/'))
{
//如果这个值包含/,我们需要计算出分数
字符串[]splitVal=fraction.Split('/');
如果(splitVal.Length!=2)
{
拧紧(分数,“拆分值长度”);
}
//把分数变成小数
value=double.Parse(splitVal[0])/double.Parse(splitVal[1]);
}
其他的
{
//否则,这是一个简单的解析
value=double.Parse(分数);
}
返回值;
}
公共静态双提取距离(字符串距离字符串)
{
双距离米=0;
/*每个单元类型都有一个匹配项。
*例如,字符串“1 1/16英里3/4码”将有两个匹配项
*“1 1/16英里”,“3/4码”。每场比赛将有4码
*组总数,第3组为原始值,第4组为原始值
*原始单位
*/
var matches=Regex.matches(distAsString,@”([\d]+[\d\s\,/]*)\s([A-Za-z]+[^\s\d]));
foreach(匹配中的匹配)
{
//如果组!=4出现问题,我们需要重新考虑正则表达式
如果(match.Groups.Count!=4)
{
搞砸了(distAsString,“match.Groups.Count”);
}
字符串valueRaw=match.Groups[2]。值;
字符串unitRaw=match.Groups[3]。值;
//首先得到价值
双值=0;
if(valueRaw.Contains(“”))
{
//如果这个值包含/,我们需要计算出分数
字符串[]splitVal=valueRaw.Split(“”);
如果(splitVal.Length!=2)
{
拧紧(分离管柱,“分离阀长度”);
}
//把分数变成小数
值=ConvertFraction(splitVal[0])+ConvertFraction(splitVal[1]);
}
其他的
{
值=换算分数(valueRaw);
}
//现在根据单位类型进行计算
//清理原始单元字符串
unitRaw=unitRaw.ToLower().Trim().TrimEnd('s');
if(!\u distance lookup.ContainsKey(unitRaw))
{
拧紧(distAsString,“unitRaw”);
}
distanceInMeters+=值*_DistanceLookup[unitRaw];
}
返回距离(米);
}
私人静空隙堵塞