@whiteslove/parsing-lexicon 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@whiteslove/parsing-lexicon",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Shared deterministic multilingual parsing lexicon for
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Shared deterministic multilingual parsing lexicon for WhitesLove housing and hiring services",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/AmoneMisa/parsing-lexicon.git"
|
|
@@ -13,6 +13,14 @@ export interface HousingListingEnrichment {
|
|
|
13
13
|
privateYard?: boolean | null;
|
|
14
14
|
dishwasher?: boolean | null;
|
|
15
15
|
airConditioner?: boolean | null;
|
|
16
|
+
tv?: boolean | null;
|
|
17
|
+
microwave?: boolean | null;
|
|
18
|
+
oven?: boolean | null;
|
|
19
|
+
bidet?: boolean | null;
|
|
20
|
+
walkInCloset?: boolean | null;
|
|
21
|
+
bathtub?: boolean | null;
|
|
22
|
+
shower?: boolean | null;
|
|
23
|
+
euroLayout?: boolean | null;
|
|
16
24
|
gas?: boolean | null;
|
|
17
25
|
newBuilding?: boolean | null;
|
|
18
26
|
communalSeparated?: boolean | null;
|
|
@@ -218,6 +218,14 @@ export function parseHousingListingEnrichment(value, { country = '' } = {}) {
|
|
|
218
218
|
privateYard: listingFields.privateYard ?? null,
|
|
219
219
|
dishwasher: listingFields.dishwasher ?? null,
|
|
220
220
|
airConditioner: listingFields.airConditioner ?? (AIR_CONDITIONER_RE.test(text) ? true : null),
|
|
221
|
+
tv: listingFields.tv ?? null,
|
|
222
|
+
microwave: listingFields.microwave ?? null,
|
|
223
|
+
oven: listingFields.oven ?? null,
|
|
224
|
+
bidet: listingFields.bidet ?? null,
|
|
225
|
+
walkInCloset: listingFields.walkInCloset ?? null,
|
|
226
|
+
bathtub: listingFields.bathtub ?? null,
|
|
227
|
+
shower: listingFields.shower ?? null,
|
|
228
|
+
euroLayout: listingFields.euroLayout ?? null,
|
|
221
229
|
gas: listingFields.gas ?? null,
|
|
222
230
|
newBuilding: listingFields.newBuilding ?? null,
|
|
223
231
|
communalSeparated: listingFields.communalSeparated ?? null,
|
|
@@ -20,6 +20,14 @@ export type HousingListingFields = Readonly<{
|
|
|
20
20
|
gazebo: boolean | null;
|
|
21
21
|
dishwasher: boolean | null;
|
|
22
22
|
airConditioner: boolean | null;
|
|
23
|
+
tv: boolean | null;
|
|
24
|
+
microwave: boolean | null;
|
|
25
|
+
oven: boolean | null;
|
|
26
|
+
bidet: boolean | null;
|
|
27
|
+
walkInCloset: boolean | null;
|
|
28
|
+
bathtub: boolean | null;
|
|
29
|
+
shower: boolean | null;
|
|
30
|
+
euroLayout: boolean | null;
|
|
23
31
|
gas: boolean | null;
|
|
24
32
|
newBuilding: boolean | null;
|
|
25
33
|
communalSeparated: boolean | null;
|
|
@@ -137,6 +137,59 @@ export function parseHousingListingFields(value, { country = '' } = {}) {
|
|
|
137
137
|
/кондицион|сплит[- ]?систем|konditsioner|kansaner|kandisaner|klimat|air\s*con|aer\s+condi[țt]ionat/iu,
|
|
138
138
|
/без\s+(?:кондицион\p{L}*|сплит[- ]?систем\p{L}*)|нет\s+(?:кондицион\p{L}*|сплит[- ]?систем\p{L}*)|(?:кондицион\p{L}*|сплит[- ]?систем\p{L}*)\s+нет|no\s+air\s*con(?:ditioner)?|konditsioner\s+yo['’]?q|кондиционер\s+йўқ/iu,
|
|
139
139
|
),
|
|
140
|
+
// "тв"/"tv" are bare 2-letter abbreviations that collide with real words
|
|
141
|
+
// (e.g. "твой" = "your") unless bounded on both sides by a non-letter --
|
|
142
|
+
// the same class of bug as the "пр" abbreviation fixed earlier in
|
|
143
|
+
// compactStreet(); do not relax these boundaries to a bare \b.
|
|
144
|
+
tv: bool(
|
|
145
|
+
text,
|
|
146
|
+
/телевизор|(?:^|[^\p{L}\p{N}_])(?:тв|tv)(?=$|[^\p{L}\p{N}_])|television|televizor/iu,
|
|
147
|
+
/без\s+телевизор\p{L}*|нет\s+телевизор\p{L}*|телевизор\p{L}*\s+нет|no\s+tv|no\s+television/iu,
|
|
148
|
+
),
|
|
149
|
+
microwave: bool(
|
|
150
|
+
text,
|
|
151
|
+
/микроволнов\p{L}*|(?:^|[^\p{L}\p{N}_])свч(?=$|[^\p{L}\p{N}_])|microwave|mikro(?:to['’]?lqinli|talqinli)\s*pech/iu,
|
|
152
|
+
/без\s+микроволнов\p{L}*|нет\s+микроволнов\p{L}*|микроволнов\p{L}*\s+нет|no\s+microwave/iu,
|
|
153
|
+
),
|
|
154
|
+
oven: bool(
|
|
155
|
+
text,
|
|
156
|
+
/духовк\p{L}*|духов\p{L}*\s+шкаф\p{L}*|oven|(?:^|[^\p{L}\p{N}_])pech(?=$|[^\p{L}\p{N}_])/iu,
|
|
157
|
+
/без\s+духовк\p{L}*|нет\s+духовк\p{L}*|духовк\p{L}*\s+нет|no\s+oven/iu,
|
|
158
|
+
),
|
|
159
|
+
bidet: bool(
|
|
160
|
+
text,
|
|
161
|
+
/биде|bidet/iu,
|
|
162
|
+
/без\s+биде|нет\s+биде|биде\s+нет|no\s+bidet/iu,
|
|
163
|
+
),
|
|
164
|
+
walkInCloset: bool(
|
|
165
|
+
text,
|
|
166
|
+
/гардеробн\p{L}*|walk[- ]?in\s+closet|dressing\s+room|garderob(?:naya)?/iu,
|
|
167
|
+
/без\s+гардеробн\p{L}*|нет\s+гардеробн\p{L}*|гардеробн\p{L}*\s+нет|no\s+walk[- ]?in\s+closet/iu,
|
|
168
|
+
),
|
|
169
|
+
// "ванна" (the tub fixture) and "ванная" (the bathroom-as-a-room) share a
|
|
170
|
+
// stem, so this only matches the shorter nominative/accusative tub forms
|
|
171
|
+
// with a hard boundary -- it will miss instrumental/genitive tub mentions
|
|
172
|
+
// ("с ванной") since those are spelled identically to the room noun and
|
|
173
|
+
// aren't safely disambiguable by regex alone.
|
|
174
|
+
bathtub: bool(
|
|
175
|
+
text,
|
|
176
|
+
/(?:^|[^\p{L}\p{N}_])(?:ванна|ванну|vanna(?:si)?)(?=$|[^\p{L}\p{N}_])|bathtub/iu,
|
|
177
|
+
/без\s+ванн\p{L}*|нет\s+ванн\p{L}*|ванн\p{L}*\s+нет|no\s+bathtub/iu,
|
|
178
|
+
),
|
|
179
|
+
shower: bool(
|
|
180
|
+
text,
|
|
181
|
+
/(?:^|[^\p{L}\p{N}_])душ(?=$|[^\p{L}\p{N}_])|душев\p{L}*\s+кабин\p{L}*|shower|dush(?:kabina)?/iu,
|
|
182
|
+
/без\s+душ\p{L}*|нет\s+душ\p{L}*|душ\p{L}*\s+нет|no\s+shower/iu,
|
|
183
|
+
),
|
|
184
|
+
// "Euro-layout" (евродвушка/евротрёшка/евро-N/европланировка) is a CIS
|
|
185
|
+
// real-estate term for an open-plan flat with the kitchen merged into the
|
|
186
|
+
// living room, as opposed to a conventional flat of the same room count
|
|
187
|
+
// with a separate closed kitchen. Positive-only: there's no common way
|
|
188
|
+
// listings state the absence of this, only its presence.
|
|
189
|
+
euroLayout: bool(
|
|
190
|
+
text,
|
|
191
|
+
/евро[- ]?(?:студи\p{L}*|двушк\p{L}*|трёшк\p{L}*|трешк\p{L}*|четырёшк\p{L}*|четрешк\p{L}*|планировк\p{L}*|[1-9](?!\p{N}))|европланировк\p{L}*|euro[- ]?layout/iu,
|
|
192
|
+
),
|
|
140
193
|
gas,
|
|
141
194
|
newBuilding: bool(text, /новостро|новобуд|новый\s+дом|novast(?:royka|iroyka)|navast(?:royka|iroyka)|new\s*build|newly\s*built|yangi\s+(?:bino|qurilgan|uy)|bloc\s+nou/iu),
|
|
142
195
|
communalSeparated: parseCommunalSeparated(text, country),
|
package/src/locations.js
CHANGED
|
@@ -172,11 +172,21 @@ export function matchDictionaryLocation(text, countryCode, city = null) {
|
|
|
172
172
|
const country = locationCities(countryCode);
|
|
173
173
|
const cities = city && country[city] ? [[city, country[city]]] : Object.entries(country);
|
|
174
174
|
const value = String(text || '');
|
|
175
|
+
let best = null;
|
|
175
176
|
for (const [cityName, data] of cities) {
|
|
176
177
|
for (const type of LOCATION_LIST_KEYS) {
|
|
177
|
-
const
|
|
178
|
-
|
|
178
|
+
for (const entry of data[type] || []) {
|
|
179
|
+
const match = entry?.re?.exec(value);
|
|
180
|
+
if (!match) continue;
|
|
181
|
+
const start = match.index;
|
|
182
|
+
const end = start + match[0].length;
|
|
183
|
+
const containsBest = best && start <= best.start && end >= best.end && end - start > best.end - best.start;
|
|
184
|
+
if (best && !containsBest) continue;
|
|
185
|
+
best = { city: cityName, type, name: entry.name, aliases: entry.aliases, start, end };
|
|
186
|
+
}
|
|
179
187
|
}
|
|
180
188
|
}
|
|
181
|
-
return null;
|
|
189
|
+
if (!best) return null;
|
|
190
|
+
const { start: _start, end: _end, ...result } = best;
|
|
191
|
+
return result;
|
|
182
192
|
}
|
|
@@ -210,6 +210,8 @@ export const UZ_LOCATION_EXTENSIONS = Object.freeze({
|
|
|
210
210
|
['Tashkent City', 'Ташкент Сити', 'Toshkent City', 'Tashkent City IBC'],
|
|
211
211
|
],
|
|
212
212
|
streets: [
|
|
213
|
+
{ name: 'Gulobod Street', aliases: ['Gulobod ko‘chasi', "Gulobod ko'chasi", 'улица Гулобод', 'ул. Гулобод'], parent: 'Shaykhantahur' },
|
|
214
|
+
{ name: 'Sebzor Street', aliases: ['Sebzor ko‘chasi', "Sebzor ko'chasi", 'улица Себзор', 'ул. Себзор'], parent: 'Almazar' },
|
|
213
215
|
{ name: 'Lolazor Street', aliases: ['Lolazor ko‘chasi', "Lolazor ko'chasi", 'улица Лолазор', 'ул. Лолазор'], parent: 'Uchtepa' },
|
|
214
216
|
{ name: 'Shohimardon Street', aliases: ['Shohimardon ko‘chasi', "Shohimardon ko'chasi", 'улица Шохимардон', 'ул. Шохимардон'], parent: 'Yashnobod' },
|
|
215
217
|
{ name: 'Shohimardon Passage 1', aliases: ['Shohimardon 1-tor ko‘chasi', "Shohimardon 1-tor ko'chasi", '1-й проезд Шохимардон', '1 проезд Шохимардон'], parent: 'Yashnobod' },
|