Сначала давайте организуем cities
; предполагая, что комбинация (City, CountryChar)
является уникальной , мы можем построить словарь:
List<CityModel> cities = ...
Dictionary<(string city, char country), CityModel> citiesDict = cities
.ToDictionary(item => (item.City, item.CountryChar),
item => item);
Затем мы должны изобрести извлечение названий городов (с возможными ложными срабатываниями * 1009) *); вероятно, last name (последовательная a..z
буква) является хорошим выбором (для этого воспользуемся регулярными выражениями ):
// will return "singapore"
IEnumerable<string> CityNames(string address) {
string name = Regex.Match(
address,
@"\b[a-z]+\b",
RegexOptions.RightToLeft | RegexOptions.IgnoreCase).Value;
if (!string.IsNullOrEmpty(name))
yield return name;
}
Или более снисходительно ( любое имен, вернет "gateway"
, "east"
, "beach"
, "road"
, "singapore"
) реализация:
IEnumerable<string> CityNames(string address) {
return Regex
.Matches(address, @"\b[a-z]+\b", RegexOptions.IgnoreCase)
.Cast<Match>()
.Select(match => match.Value);
}
Затем мы можем построить окончательный Linq с помощью SelectMany
:
List<AddressModel> addresses = ...
var result = addresses
.SelectMany(item => CityNames(item.Address) // match all possible cities form address
.Select(possibleCity => new { // actual city from possible city
address = item,
city = citiesDict.TryGetValue((possibleCity, item.CountryChar),
out var actualCity)
? actualCity // Either Real City (if found), say, "singapore"
: null // null if not exits, say, "road"
}))
.Where(item => item.city != null); // Real City Only
Редактировать: Основная сложность здесь заключается в извлечении потенциальных названий городов ( Обработка естественного языка в общем случае ...). Если вы можете гарантировать, что части адреса (улица, город, страна и т. Д. c.) Разделены запятой ,
, мы можем попробовать Split
:
IEnumerable<string> CityNames(string address) {
return address
.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(item => Regex.Replace(item.Trim(), @"\s+", " ").ToLower())
.Where(item => !string.IsNullOrEmpty(item));
}
Теперь для "1st Floor, 6, quai Antoine-1er Le Ruscino, 98012 Monte Carlo, CEDEX, Monaco"
мы ' будет иметь "1st floor"
"6"
"quai antoine-1er le ruscino"
"98012 monte carlo"
, "cedex"
, "monaco"
. Обратите внимание, что 98012
добавлено к Monte Carlo
. Если вы хотите полосы номеров и иметь "st floor"
, "quai antoine-er le ruscino"
"monte carlo"
, "cedex"
, "monaco"
IEnumerable<string> CityNames(string address) {
return address
.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(item => Regex.Replace(item, "[0-9]+", ""))
.Select(item => Regex.Replace(item.Trim(), @"\s+", " ").ToLower())
.Where(item => !string.IsNullOrEmpty(item));
}