| 394 | |
| 395 | template <class ObjT, class GetKeyFnT> |
| 396 | std::optional<uint32_t> MatchObjectByName(std::string_view keyName, std::vector<ObjT> const & objs, GetKeyFnT && getKey) |
| 397 | { |
| 398 | size_t constexpr kSimilarityThresholdPercent = 10; |
| 399 | |
| 400 | // Find the exact match or the best match in kSimilarityTresholdPercent limit. |
| 401 | uint32_t result; |
| 402 | size_t minPercent = kSimilarityThresholdPercent + 1; |
| 403 | |
| 404 | auto const key = getKey(keyName); |
| 405 | for (auto const & obj : objs) |
| 406 | { |
| 407 | bool fullMatchFound = false; |
| 408 | obj.m_multilangName.ForEach([&](int8_t lang, std::string_view name) |
| 409 | { |
| 410 | if (fullMatchFound) |
| 411 | return; |
| 412 | |
| 413 | // Skip _non-language_ names for street<->address matching. |
| 414 | if (localisation::IsAlternativeOrOldName(lang)) |
| 415 | return; |
| 416 | |
| 417 | strings::UniString const actual = getKey(name); |
| 418 | size_t const editDistance = strings::EditDistance(key.begin(), key.end(), actual.begin(), actual.end()); |
| 419 | |
| 420 | if (editDistance == 0) |
| 421 | { |
| 422 | result = obj.m_id.m_index; |
| 423 | fullMatchFound = true; |
| 424 | return; |
| 425 | } |
| 426 | |
| 427 | if (actual.empty()) |
| 428 | return; |
| 429 | |
| 430 | size_t const percent = editDistance * 100 / actual.size(); |
| 431 | if (percent < minPercent) |
| 432 | { |
| 433 | result = obj.m_id.m_index; |
| 434 | minPercent = percent; |
| 435 | } |
| 436 | }); |
| 437 | |
| 438 | if (fullMatchFound) |
| 439 | return result; |
| 440 | } |
| 441 | |
| 442 | if (minPercent <= kSimilarityThresholdPercent) |
| 443 | return result; |
| 444 | return {}; |
| 445 | } |
| 446 | |
| 447 | void BuildAddressTable(FilesContainerR & container, std::string const & addressDataFile, Writer & streetsWriter, |
| 448 | Writer & placesWriter, uint32_t threadsCount) |
no test coverage detected