Normalize project locations against variations and common typos

This commit is contained in:
2025-01-28 22:33:58 +01:00
parent 5e2403b486
commit 369ac98d0e
2 changed files with 72 additions and 13 deletions
+47 -8
View File
@@ -5,9 +5,9 @@ namespace App\Benzina;
trait ProjectsPumpTrait
{
/**
* Cleans the project location field to obtain better and more cacheable search queries.
* Cleans the project location field to obtain highly cacheable and improved search queries.
* Based on analysis of the Goteo v3 `project.project_location` values.
*
*
* @param int $detailLevel Desired number of remaining components in output address
*/
public static function cleanProjectLocation(string $location, int $detailLevel = 3): string
@@ -23,7 +23,7 @@ trait ProjectsPumpTrait
// Remove secondary conjoined places from locations
// e.g: "España y el mundo" -> "España"
foreach ([' / ', ' | ', ' - ', ' y ', ' and '] as $conjoinment) {
foreach ([' / ', ' | ', ' - ', ' y ', ' and ', ' & '] as $conjoinment) {
if (\str_contains($location, $conjoinment)) {
$location = \explode($conjoinment, $location)[0];
}
@@ -41,13 +41,30 @@ trait ProjectsPumpTrait
// Clean non desired location pieces
$location = \explode(',', $location);
$location = \array_map(fn($l) => trim($l), $location);
$location = \array_map(function ($l) {
$l = trim($l);
// Normalize typos and name variations
foreach (self::COMMON_VARIATIONS as $standard => $variations) {
if (in_array(\mb_strtoupper($l), $variations)) {
$l = $standard;
}
}
return $l;
}, $location);
$location = \array_filter($location, function ($l) {
if (empty($l)) return false;
if (empty($l)) {
return false;
}
// Skip numeric only pieces: coordinates, street numbers, etc
if (\preg_match('/^[-\d.]*$/', $l)) return false;
if (\str_contains($l, 'º')) return false;
if (\preg_match('/^[-\d.]*$/', $l)) {
return false;
}
if (\str_contains($l, 'º')) {
return false;
}
return true;
});
@@ -59,6 +76,28 @@ trait ProjectsPumpTrait
return \mb_strtoupper(\trim($location));
}
/**
* @var array<string, array> The standard preferred name and a list of possible variations and misspellings
*/
private const COMMON_VARIATIONS = [
'ESPAÑA' => ['ESPANYA', 'ESPANHA', 'ESPAGNE', 'SPAGNA', 'SPANIEN', 'SPAIN'],
'CATALUÑA' => ['CATALUNYA', 'PAÏSOS CATALANS'],
'ANDALUCÍA' => ['ANDALUCIA', 'ANDALUSIA'],
'FRANCIA' => ['FRANCE'],
'ITALIA' => ['ITALY'],
'ALEMANIA' => ['GERMANY'],
'CÁDIZ' => ['CADIZ'],
'VALENCIA' => ['VALÈNCIA', 'PROVINCIA DE VALENCIA'],
'ALICANTE' => ['ALACANT'],
'CÁCERES' => ['CACERES'],
'BALEARES' => ['BALEAREN', 'ISLAS BALEARES', 'ILLES BALEARS', 'BALEARIC ISLANDS'],
'GALICIA' => ['GALIZA'],
'BILBAO' => ['BILBO'],
'LLEIDA' => ['LÉRIDA'],
'BARCELONA' => ['PROVINCIA DE BARCELONA'],
'MURCIA' => ['REGIÓN DE MURCIA'],
];
private const PROJECT_KEYS = [
'id',
'name',
+25 -5
View File
@@ -37,7 +37,7 @@ class ProjectsPumpTraitTest extends TestCase
['http://www.ecologiaperumanu.com/mapaproyecto.php'],
['http://www.esbaluard.org/es/'],
['https://www.google.es/maps/@40.0320175,-5.7727571,500m/data=!3m1!1e3'],
['www.google.com/maps/place/Tecoanapa,+Gro./@16.9873264,-99.2593372,18.25z/data=!4m5!3m4!1s0x85ca2be1bd85bfcd:0xd3cb17e67573bf44!8m2!3d16.9865731!4d-99.2604936']
['www.google.com/maps/place/Tecoanapa,+Gro./@16.9873264,-99.2593372,18.25z/data=!4m5!3m4!1s0x85ca2be1bd85bfcd:0xd3cb17e67573bf44!8m2!3d16.9865731!4d-99.2604936'],
];
}
@@ -50,7 +50,7 @@ class ProjectsPumpTraitTest extends TestCase
$this->assertEquals($finalAddress, $cleanAddress);
}
public function provideConjoinedAddresses(): array
{
return [
@@ -58,7 +58,7 @@ class ProjectsPumpTraitTest extends TestCase
['buenos aires, argentina y barcelona españa', 'BUENOS AIRES, ARGENTINA'],
['Barcelona y Bilbao', 'BARCELONA'],
['Madrid, España / San Francisco, EEUU', 'MADRID, ESPAÑA'],
['Calafou, Camí de Ca la Fou, s/n | CP: 08785 | Vallbona d´Anoia (Barcelona)', 'CALAFOU, CAMÍ DE CA LA FOU, S/N']
['Calafou, Camí de Ca la Fou, s/n | CP: 08785 | Vallbona d´Anoia (Barcelona)', 'CALAFOU, CAMÍ DE CA LA FOU, S/N'],
];
}
@@ -68,7 +68,7 @@ class ProjectsPumpTraitTest extends TestCase
public function testStripsColonSpecifiers($colonSpecified, $removedSpecifier)
{
$cleanAddress = $this->pump->cleanProjectLocation($colonSpecified);
$this->assertStringNotContainsString($removedSpecifier, $cleanAddress);
}
@@ -96,7 +96,27 @@ class ProjectsPumpTraitTest extends TestCase
return [
[', Cali, Colombia', 'CALI, COLOMBIA'],
['Lobres (Granada', 'LOBRES, GRANADA'],
['California City, California, EE. UU.', 'CALIFORNIA CITY, CALIFORNIA, EE. UU']
['California City, California, EE. UU.', 'CALIFORNIA CITY, CALIFORNIA, EE. UU'],
];
}
/**
* @dataProvider provideCountryVariations
*/
public function testStandarisesCountry($variation, $standard)
{
$cleanAddress = $this->pump->cleanProjectLocation($variation);
$this->assertEquals($standard, $cleanAddress);
}
public function provideCountryVariations(): array
{
return [
['SPAIN', 'ESPAÑA'],
['MADRID, ESPAÑA', 'MADRID, ESPAÑA'],
['MADRID, ESPANYA', 'MADRID, ESPAÑA'],
['MADRID, ESPAGNE', 'MADRID, ESPAÑA'],
];
}
}