]> git.openstreetmap.org Git - nominatim.git/blob - lib/Phrase.php
Merge pull request #1126 from lonvia/improve-country-reverse
[nominatim.git] / lib / Phrase.php
1 <?php
2
3 namespace Nominatim;
4
5 /**
6  * Segment of a query string.
7  *
8  * The parts of a query strings are usually separated by commas.
9  */
10 class Phrase
11 {
12     const MAX_DEPTH = 7;
13
14     // Complete phrase as a string.
15     private $sPhrase;
16     // Element type for structured searches.
17     private $sPhraseType;
18     // Space-separated words of the phrase.
19     private $aWords;
20     // Possible segmentations of the phrase.
21     private $aWordSets;
22
23
24     public function __construct($sPhrase, $sPhraseType)
25     {
26         $this->sPhrase = trim($sPhrase);
27         $this->sPhraseType = $sPhraseType;
28         $this->aWords = explode(' ', $this->sPhrase);
29         $this->aWordSets = $this->createWordSets($this->aWords, 0);
30     }
31
32     /**
33      * Return the element type of the phrase.
34      *
35      * @return string Pharse type if the phrase comes from a structured query
36      *                or empty string otherwise.
37      */
38     public function getPhraseType()
39     {
40         return $this->sPhraseType;
41     }
42
43     /**
44      * Return the array of possible segmentations of the phrase.
45      *
46      * @return string[][] Array of segmentations, each consisting of an
47      *                    array of terms.
48      */
49     public function getWordSets()
50     {
51         return $this->aWordSets;
52     }
53
54     /**
55      * Add the tokens from this phrase to the given list of tokens.
56      *
57      * @param string[] $aTokens List of tokens to append.
58      *
59      * @return void
60      */
61     public function addTokens(&$aTokens)
62     {
63         foreach ($this->aWordSets as $aSet) {
64             foreach ($aSet as $sWord) {
65                 $aTokens[' '.$sWord] = ' '.$sWord;
66                 $aTokens[$sWord] = $sWord;
67             }
68         }
69     }
70
71     /**
72      * Invert the set of possible segmentations.
73      *
74      * @return void
75      */
76     public function invertWordSets()
77     {
78         $this->aWordSets = $this->createInverseWordSets($this->aWords, 0);
79     }
80
81     private function createWordSets($aWords, $iDepth)
82     {
83         $aResult = array(array(join(' ', $aWords)));
84         $sFirstToken = '';
85         if ($iDepth < Phrase::MAX_DEPTH) {
86             while (count($aWords) > 1) {
87                 $sWord = array_shift($aWords);
88                 $sFirstToken .= ($sFirstToken?' ':'').$sWord;
89                 $aRest = $this->createWordSets($aWords, $iDepth + 1);
90                 foreach ($aRest as $aSet) {
91                     $aResult[] = array_merge(array($sFirstToken), $aSet);
92                 }
93             }
94         }
95
96         return $aResult;
97     }
98
99     private function createInverseWordSets($aWords, $iDepth)
100     {
101         $aResult = array(array(join(' ', $aWords)));
102         $sFirstToken = '';
103         if ($iDepth < Phrase::MAX_DEPTH) {
104             while (count($aWords) > 1) {
105                 $sWord = array_pop($aWords);
106                 $sFirstToken = $sWord.($sFirstToken?' ':'').$sFirstToken;
107                 $aRest = $this->createInverseWordSets($aWords, $iDepth + 1);
108                 foreach ($aRest as $aSet) {
109                     $aResult[] = array_merge(array($sFirstToken), $aSet);
110                 }
111             }
112         }
113
114         return $aResult;
115     }
116
117     public function debugInfo()
118     {
119         return array(
120                 'Type' => $this->sPhraseType,
121                 'Phrase' => $this->sPhrase,
122                 'Words' => $this->aWords,
123                 'WordSets' => $this->aWordSets
124                );
125     }
126 }