cry-vetzdravila 1.0.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/.claude/settings.local.json +17 -0
- package/CLAUDE.md +82 -0
- package/LICENSE.md +16 -0
- package/README.md +376 -0
- package/a.txt +1643 -0
- package/bun.lock +197 -0
- package/dist/atcvet/opisATCvetKode.d.ts +23 -0
- package/dist/atcvet/podatkiATCvetKode.d.ts +20 -0
- package/dist/atcvet/pomeniNivojevATCvet.d.ts +1 -0
- package/dist/atcvet/types/AtcvetFile.d.ts +19 -0
- package/dist/generated/AtcVet.d.ts +9 -0
- package/dist/generated/RegisterZdravil.d.ts +8 -0
- package/dist/generated/seznamZdravil.d.ts +8 -0
- package/dist/index.d.ts +244 -0
- package/dist/index.js +141786 -0
- package/dist/register/MIN_OCENA_PODOBNOSTI.d.ts +2 -0
- package/dist/register/helper/normalizirajNaziv.d.ts +176 -0
- package/dist/register/helper/oblikujRezultatIskanja.d.ts +8 -0
- package/dist/register/helper/oceniPodobnost.d.ts +37 -0
- package/dist/register/helper/poisciZivalskoVrsto.d.ts +33 -0
- package/dist/register/helper/razcleniNaziv.d.ts +2 -0
- package/dist/register/podobnaZdravilaPoATC.d.ts +16 -0
- package/dist/register/podobnaZdravilaPoUcinkovinah.d.ts +18 -0
- package/dist/register/registerZdravil.d.ts +9 -0
- package/dist/register/types/KarencaZdravila.d.ts +24 -0
- package/dist/register/types/PotUporabeZdravila.d.ts +21 -0
- package/dist/register/types/RazclembaZdravila.d.ts +9 -0
- package/dist/register/types/RegisterZdravil.d.ts +2 -0
- package/dist/register/types/UcinkovinaZdravila.d.ts +20 -0
- package/dist/register/types/Zdravilo.d.ts +65 -0
- package/dist/register/types/ZdraviloZUtemeljitvijo.d.ts +9 -0
- package/dist/register/types/ZivalskeVrste.d.ts +158 -0
- package/dist/register/uganiZdravilo.d.ts +43 -0
- package/dist/register/zdravilaZaAtcVetKodo.d.ts +8 -0
- package/dist/register/zdraviloJeVakcinaZa.d.ts +18 -0
- package/docs/vakcine.md +195 -0
- package/package.json +39 -0
- package/src/atcvet/CLAUDE.md +18 -0
- package/src/atcvet/downloadLatestAtcvetPdf.ts +107 -0
- package/src/atcvet/opisATCvetKode.ts +116 -0
- package/src/atcvet/parseAtcvetPdf.ts +215 -0
- package/src/atcvet/podatkiATCvetKode.ts +34 -0
- package/src/atcvet/pomeniNivojevATCvet.ts +8 -0
- package/src/atcvet/types/AtcvetFile.ts +22 -0
- package/src/generate.ts +111 -0
- package/src/generated/AtcVet.ts +56704 -0
- package/src/generated/seznamZdravil.ts +44833 -0
- package/src/importParseAndBuildAll.ts +97 -0
- package/src/index.ts +289 -0
- package/src/interactive.ts +428 -0
- package/src/register/CLAUDE.md +230 -0
- package/src/register/MIN_OCENA_PODOBNOSTI.ts +3 -0
- package/src/register/downloadRegister.ts +148 -0
- package/src/register/helper/analizaVakcin.ts +90 -0
- package/src/register/helper/checkVrste.ts +72 -0
- package/src/register/helper/hashString.ts +27 -0
- package/src/register/helper/normalizirajNaziv.ts +493 -0
- package/src/register/helper/oblikujRezultatIskanja.ts +15 -0
- package/src/register/helper/oceniPodobnost.ts +194 -0
- package/src/register/helper/poisciZivalskoVrsto.ts +100 -0
- package/src/register/helper/razcleniNaziv.ts +105 -0
- package/src/register/helper/testNormalizacije.ts +89 -0
- package/src/register/helper/testPodobnosti.ts +238 -0
- package/src/register/helper/testVakcin.ts +103 -0
- package/src/register/parseRegister.ts +464 -0
- package/src/register/podobnaZdravilaPoATC.ts +71 -0
- package/src/register/podobnaZdravilaPoUcinkovinah.ts +136 -0
- package/src/register/registerZdravil.ts +22 -0
- package/src/register/stats.ts +114 -0
- package/src/register/types/KarencaZdravila.ts +26 -0
- package/src/register/types/PotUporabeZdravila.ts +21 -0
- package/src/register/types/RazclembaZdravila.ts +10 -0
- package/src/register/types/RegisterRaw.ts +23 -0
- package/src/register/types/RegisterZdravil.ts +3 -0
- package/src/register/types/UcinkovinaZdravila.ts +21 -0
- package/src/register/types/Zdravilo.ts +84 -0
- package/src/register/types/ZdraviloZUtemeljitvijo.ts +11 -0
- package/src/register/types/ZivalskeVrste.ts +7 -0
- package/src/register/uganiZdravilo.ts +142 -0
- package/src/register/zdravilaZaAtcVetKodo.ts +28 -0
- package/src/register/zdraviloJeVakcinaZa.ts +202 -0
- package/src/test/testPodobnosti.test.ts +126 -0
- package/src/test/zdravila.json +38693 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizacija naziva zdravila
|
|
3
|
+
*
|
|
4
|
+
* Čiščenje in normalizacija imen zdravil za boljše iskanje.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Enote za doziranje
|
|
9
|
+
*/
|
|
10
|
+
const ENOTE = [
|
|
11
|
+
"g", "mg", "mcg", "kg", "l", "ml", "dl", "deci", "ie", "tbl",
|
|
12
|
+
"cap", "caps", "kap", "kps", "kaps", "kapsula", "kapsul",
|
|
13
|
+
"doz", "doza", "doze",
|
|
14
|
+
"tub", "tubi", "tube", "tuba",
|
|
15
|
+
"ser",
|
|
16
|
+
"kos", "kosov", "kosa", "kosi",
|
|
17
|
+
"kom", "komadov", "komada", "komadi", "komad"
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Enote za količino (brez g, mg, mcg, kg, ml, dl, ie)
|
|
22
|
+
* Uporablja se za prepoznavanje količine na koncu naziva
|
|
23
|
+
*/
|
|
24
|
+
const ENOTE_KOLICINE = [
|
|
25
|
+
"tbl",
|
|
26
|
+
"cap", "caps", "kap", "kps", "kaps", "kapsula", "kapsul",
|
|
27
|
+
"doz", "doza", "doze",
|
|
28
|
+
"tub", "tubi", "tube", "tuba",
|
|
29
|
+
"ser",
|
|
30
|
+
"kos", "kosov", "kosa", "kosi",
|
|
31
|
+
"kom", "komadov", "komada", "komadi", "komad"
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 1. Pretvori v male črke za slovensko lokalizacijo
|
|
36
|
+
*/
|
|
37
|
+
function toLowerCaseSL(text: string): string {
|
|
38
|
+
return text.toLocaleLowerCase("sl-SI");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 2. Zamenjaj posebne znake + ( ) , ; * s presledki
|
|
43
|
+
*/
|
|
44
|
+
function replaceSpecialChars(text: string): string {
|
|
45
|
+
return text.replace(/[+(),;*]/g, " ");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 3. Zamenjaj decimalne vejice med dvema številkama z decimalno piko
|
|
50
|
+
* Primer: "50,5" → "50.5"
|
|
51
|
+
*/
|
|
52
|
+
function replaceDecimalCommas(text: string): string {
|
|
53
|
+
return text.replace(/(\d),(\d)/g, "$1.$2");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 4. Zamenjaj i.e. z ie
|
|
58
|
+
*/
|
|
59
|
+
function replaceIE(text: string): string {
|
|
60
|
+
return text.replace(/i\.e\./gi, "ie");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 5. Zamenjaj tablete, tablet, tabl, tableta, tab → tbl
|
|
65
|
+
*/
|
|
66
|
+
function normalizeTablete(text: string): string {
|
|
67
|
+
return text.replace(/\b(tablete|tablet|tableta|tabl|tab)\b/gi, "tbl");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 5b. Zamenjaj cap, caps, kap, kaps, kapsula, kapsul → kps
|
|
72
|
+
*/
|
|
73
|
+
function normalizeKapsule(text: string): string {
|
|
74
|
+
return text.replace(/\b(kapsul[ae]?|kaps|kap|caps|cap)\b/gi, "kps");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 5c. Zamenjaj deci → dl
|
|
79
|
+
*/
|
|
80
|
+
function normalizeDeci(text: string): string {
|
|
81
|
+
return text.replace(/\bdeci\b/gi, "dl");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 5d. Zamenjaj doza, doze → doz
|
|
86
|
+
*/
|
|
87
|
+
function normalizeDoz(text: string): string {
|
|
88
|
+
return text.replace(/\b(doza|doze)\b/gi, "doz");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 5d. Zamenjaj tube, tubi, tuba → tub
|
|
93
|
+
*/
|
|
94
|
+
function normalizeTub(text: string): string {
|
|
95
|
+
return text.replace(/\b(tube|tubi|tuba)\b/gi, "tub");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 5e. Zamenjaj kosov, kosa, kosi → kos
|
|
100
|
+
*/
|
|
101
|
+
function normalizeKos(text: string): string {
|
|
102
|
+
return text.replace(/\b(kosov|kosa|kosi)\b/gi, "kos");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 5f. Zamenjaj kom, komad, komada, komadi, komadov → kos
|
|
107
|
+
*/
|
|
108
|
+
function normalizeKom(text: string): string {
|
|
109
|
+
return text.replace(/\b(komadov|komada|komadi|komad|kom)\b/gi, "kos");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 6. Odstrani pike za enotami
|
|
114
|
+
* Primer: "100 gr." → "100 gr"
|
|
115
|
+
*/
|
|
116
|
+
function removeDotsAfterUnits(text: string): string {
|
|
117
|
+
const enotaPattern = ENOTE.join("|");
|
|
118
|
+
const regex = new RegExp(`(${enotaPattern})\\.(?!\\d)`, "gi");
|
|
119
|
+
return text.replace(regex, "$1");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 5. Izbriši presledke med številko in enoto / enoto
|
|
124
|
+
* Primer: "100 mg / g" → "100mg/g", "160 mg/ml" → "160mg/ml", "330 mg / 100 mg" → "330mg/100mg"
|
|
125
|
+
*/
|
|
126
|
+
function normalizeUnitSlash(text: string): string {
|
|
127
|
+
const enotaPattern = ENOTE.join("|");
|
|
128
|
+
|
|
129
|
+
// Vzorec 1: številka enota / številka enota (z ali brez presledkov)
|
|
130
|
+
// Primer: "330 mg / 100 mg" → "330mg/100mg"
|
|
131
|
+
const regex1 = new RegExp(
|
|
132
|
+
`(\\d+(?:\\.\\d+)?)\\s*(${enotaPattern})\\s*/\\s*(\\d+(?:\\.\\d+)?)\\s*(${enotaPattern})`,
|
|
133
|
+
"gi"
|
|
134
|
+
);
|
|
135
|
+
let result = text.replace(regex1, "$1$2/$3$4");
|
|
136
|
+
|
|
137
|
+
// Vzorec 2: številka enota / enota (z ali brez presledkov okoli /)
|
|
138
|
+
// Primer: "160 mg/ml" → "160mg/ml", "100 mg / g" → "100mg/g"
|
|
139
|
+
const regex2 = new RegExp(`(\\d+(?:\\.\\d+)?)\\s*(${enotaPattern})\\s*/\\s*(${enotaPattern})`, "gi");
|
|
140
|
+
result = result.replace(regex2, "$1$2/$3");
|
|
141
|
+
|
|
142
|
+
// Vzorec 3: enota / enota (brez številke, z ali brez presledkov)
|
|
143
|
+
// Primer: "mg / ml" → "mg/ml"
|
|
144
|
+
const regex3 = new RegExp(`(${enotaPattern})\\s*/\\s*(${enotaPattern})`, "gi");
|
|
145
|
+
result = result.replace(regex3, "$1/$2");
|
|
146
|
+
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 6. Izbriši presledke med številko in enoto
|
|
152
|
+
* Primer: "50.5 mg" → "50.5mg", "200 mg 50 mg" → "200mg 50mg"
|
|
153
|
+
*/
|
|
154
|
+
function normalizeUnitSpaces(text: string): string {
|
|
155
|
+
const enotaPattern = ENOTE.join("|");
|
|
156
|
+
const regex = new RegExp(`(\\d+(?:\\.\\d+)?)\\s+(${enotaPattern})(?![a-z])`, "gi");
|
|
157
|
+
return text.replace(regex, "$1$2");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 7. Zamenjaj pike pred enoto s presledki
|
|
162
|
+
* Primer: "inj.100ml" → "inj 100ml"
|
|
163
|
+
* Ohrani decimalne pike (pika med dvema številkama)
|
|
164
|
+
*/
|
|
165
|
+
function replaceDotsBeforeUnits(text: string): string {
|
|
166
|
+
const enotaPattern = ENOTE.join("|");
|
|
167
|
+
// Zahtevaj črko pred piko, da ne zamenjamo decimalnih pik
|
|
168
|
+
const regex = new RegExp(`([a-zA-ZčšžćđČŠŽĆĐ])\\.(\\d+(?:\\.\\d+)?(?:${enotaPattern}))`, "gi");
|
|
169
|
+
return text.replace(regex, "$1 $2");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 7b. Odstrani vse pike pred presledkom
|
|
174
|
+
* Primer: "inj. 100ml" → "inj 100ml"
|
|
175
|
+
*/
|
|
176
|
+
function removeDotsBeforeSpaces(text: string): string {
|
|
177
|
+
return text.replace(/\.\s+/g, " ");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 13. Odstrani vse pike za črkami
|
|
182
|
+
* Primer: "inj." → "inj", "sol." → "sol"
|
|
183
|
+
*/
|
|
184
|
+
function removeDotsAfterLetters(text: string): string {
|
|
185
|
+
return text.replace(/([a-zA-ZčšžćđČŠŽĆĐ])\./g, "$1");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* 14. Zamenjaj pike med črkami s presledki
|
|
190
|
+
* Primer: "ANTIPAR.ŠAMPON" → "ANTIPAR ŠAMPON"
|
|
191
|
+
*/
|
|
192
|
+
function replaceDotsWithSpaces(text: string): string {
|
|
193
|
+
return text.replace(/([a-zA-ZčšžćđČŠŽĆĐ])\.([a-zA-ZčšžćđČŠŽĆĐ])/g, "$1 $2");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* 15. Zamenjaj enoto gr z g
|
|
198
|
+
* Primer: "10gr" → "10g", "100gr/ml" → "100g/ml"
|
|
199
|
+
*/
|
|
200
|
+
function normalizeGr(text: string): string {
|
|
201
|
+
return text.replace(/(\d)gr\b/gi, "$1g");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Pomožna funkcija za odstranitev decimalk pri teži >= 1kg
|
|
206
|
+
* "40.1" → "40", "0.5" → "0.5" (ohrani za < 1kg)
|
|
207
|
+
*/
|
|
208
|
+
function removeDecimalIfOver1kg(val: string): string {
|
|
209
|
+
const normalized = val.replace(",", ".");
|
|
210
|
+
const num = parseFloat(normalized);
|
|
211
|
+
if (num >= 1) {
|
|
212
|
+
return Math.floor(num).toString();
|
|
213
|
+
}
|
|
214
|
+
return normalized;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 7. Strni teže živali v kg
|
|
219
|
+
* Primeri:
|
|
220
|
+
* - "od 40,1 do 60,0 kg" → "40-60kg"
|
|
221
|
+
* - "od 40,1 kg do 60,0 kg" → "40-60kg"
|
|
222
|
+
* - "nad 40,1 kg" → "40kg-"
|
|
223
|
+
* - "vsaj 40 kg" → "40kg-"
|
|
224
|
+
* - "najmanj 5 kg" → "5kg-"
|
|
225
|
+
* - "pod 40,1 kg" → "-40kg"
|
|
226
|
+
* - "do 40,1 kg" → "-40kg"
|
|
227
|
+
* - "največ 40 kg" → "-40kg"
|
|
228
|
+
* - "od 40kg - 60kg" → "40-60kg"
|
|
229
|
+
* Decimalke se odstranijo za teže >= 1kg
|
|
230
|
+
*/
|
|
231
|
+
function normalizeWeightRanges(text: string): string {
|
|
232
|
+
let result = text;
|
|
233
|
+
|
|
234
|
+
// "od X do Y kg" ali "od X kg do Y kg"
|
|
235
|
+
result = result.replace(
|
|
236
|
+
/od\s+(\d+(?:[.,]\d+)?)\s*(?:kg\s+)?do\s+(\d+(?:[.,]\d+)?)\s*kg/gi,
|
|
237
|
+
(_, from, to) => `${removeDecimalIfOver1kg(from)}-${removeDecimalIfOver1kg(to)}kg`
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
// "od Xkg - Ykg" (z vezajem)
|
|
241
|
+
result = result.replace(
|
|
242
|
+
/od\s+(\d+(?:[.,]\d+)?)\s*kg\s*-\s*(\d+(?:[.,]\d+)?)\s*kg/gi,
|
|
243
|
+
(_, from, to) => `${removeDecimalIfOver1kg(from)}-${removeDecimalIfOver1kg(to)}kg`
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
// "nad X kg" ali "vsaj X kg" ali "najmanj X kg" (od te teže naprej)
|
|
247
|
+
result = result.replace(/(?:nad|vsaj|najmanj)\s+(\d+(?:[.,]\d+)?)\s*kg/gi, (_, val) => `${removeDecimalIfOver1kg(val)}kg-`);
|
|
248
|
+
|
|
249
|
+
// "pod X kg" ali "do X kg" ali "največ X kg" (do te teže)
|
|
250
|
+
result = result.replace(/(?:pod|do|največ)\s+(\d+(?:[.,]\d+)?)\s*kg/gi, (_, val) => `-${removeDecimalIfOver1kg(val)}kg`);
|
|
251
|
+
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* 17. Dodaj kg za vsako številko v teži
|
|
256
|
+
* Primer: "40-60kg" → "40kg-60kg", "-40kg" → "-40kg", "40kg-" → "40kg-"
|
|
257
|
+
*/
|
|
258
|
+
function addKgToWeight(text: string): string {
|
|
259
|
+
// Vzorec za razpon tež: X-Ykg → Xkg-Ykg
|
|
260
|
+
let result = text.replace(/(\d+)-(\d+)kg/g, "$1kg-$2kg");
|
|
261
|
+
// Vzorec za teže brez kg na prvi številki: -Xkg ostane -Xkg (že pravilno)
|
|
262
|
+
// Vzorec za teže brez kg na zadnji številki: Xkg- ostane Xkg- (že pravilno)
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 10. Odstrani " za "
|
|
268
|
+
*/
|
|
269
|
+
function removeZa(text: string): string {
|
|
270
|
+
return text.replace(/\s+za\s+/gi, " ");
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* 19. Normalizira količine na koncu naziva
|
|
275
|
+
* - Odstrani presledke okrog x ali *
|
|
276
|
+
* - Zamenja a/á + številka → številka (brez a/á)
|
|
277
|
+
* - Odstrani začetni x pred številko
|
|
278
|
+
* - Če je številka "1", jo odstrani
|
|
279
|
+
* Primeri:
|
|
280
|
+
* - "zdravilo 10 x 5" → "zdravilo 10x5"
|
|
281
|
+
* - "zdravilo 5 * 10" → "zdravilo 5*10"
|
|
282
|
+
* - "zdravilo a 7 tbl" → "zdravilo 7tbl"
|
|
283
|
+
* - "zdravilo á7tbl" → "zdravilo 7tbl"
|
|
284
|
+
* - "ypozane 15mg x7tbl" → "ypozane 15mg 7tbl"
|
|
285
|
+
* - "1kom" → "kom"
|
|
286
|
+
*/
|
|
287
|
+
function normalizeTrailingQuantity(text: string): string {
|
|
288
|
+
let result = text;
|
|
289
|
+
// Odstrani presledke okrog x ali *
|
|
290
|
+
result = result.replace(/(\d+)\s*[x×]\s*(\d+)/gi, "$1x$2");
|
|
291
|
+
result = result.replace(/(\d+)\s*\*\s*(\d+)/g, "$1*$2");
|
|
292
|
+
// Zamenja a/á + morda presledki + številka → številka (brez a/á)
|
|
293
|
+
// Uporabi (?<![a-zA-ZčšžćđČŠŽĆĐ]) namesto \b ker \b ne deluje z á
|
|
294
|
+
result = result.replace(/(?<![a-zA-ZčšžćđČŠŽĆĐ])[aá]\s*(\d+)/gi, "$1");
|
|
295
|
+
// Odstrani začetni x pred številko (x7tbl → 7tbl)
|
|
296
|
+
result = result.replace(/\bx(\d+)/gi, "$1");
|
|
297
|
+
// Če je številka "1" pred enoto, jo odstrani (1kom → kom)
|
|
298
|
+
const enotaPattern = ENOTE.join("|");
|
|
299
|
+
const regex1 = new RegExp(`\\b1(${enotaPattern})\\b`, "gi");
|
|
300
|
+
result = result.replace(regex1, "$1");
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 12. Zamenjaj " / " s presledki
|
|
306
|
+
* Dodaj presledek na konec, nato zamenjaj vse " / " s presledki
|
|
307
|
+
* Primer: "zdravilo / oblika" → "zdravilo oblika"
|
|
308
|
+
*/
|
|
309
|
+
function replaceSlashWithSpace(text: string): string {
|
|
310
|
+
return (text + " ").replace(/\s+\/\s+/g, " ");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* 13. Zamenjaj živalske vrste
|
|
315
|
+
* psi, pse, psa → pse
|
|
316
|
+
* mačko, mačka, mačke → mačke
|
|
317
|
+
* krava, krave, telice → govedo
|
|
318
|
+
*/
|
|
319
|
+
function normalizeAnimalSpecies(text: string): string {
|
|
320
|
+
return text
|
|
321
|
+
.replace(/\b(psi|psa)\b/gi, "pse")
|
|
322
|
+
.replace(/\b(mačko|mačka)\b/gi, "mačke")
|
|
323
|
+
.replace(/\b(krava|krave|telice)\b/gi, "govedo");
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* 14. Odstrani vse znake / za presledkom
|
|
328
|
+
* Primer: "zdravilo / test" → "zdravilo test" (že urejeno z replaceSlashWithSpace)
|
|
329
|
+
* Primer: "zdravilo /" → "zdravilo"
|
|
330
|
+
*/
|
|
331
|
+
function removeSlashAfterSpace(text: string): string {
|
|
332
|
+
return text.replace(/\s+\/\s*/g, " ").replace(/\s+\/$/g, "");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Glavna funkcija za normalizacijo naziva
|
|
338
|
+
*/
|
|
339
|
+
export function normalizirajNaziv(naziv: string): string {
|
|
340
|
+
let result = naziv;
|
|
341
|
+
|
|
342
|
+
// 1. Male črke
|
|
343
|
+
result = toLowerCaseSL(result);
|
|
344
|
+
|
|
345
|
+
// 2. Odstrani " za "
|
|
346
|
+
result = removeZa(result);
|
|
347
|
+
|
|
348
|
+
// 3. Decimalne vejice
|
|
349
|
+
result = replaceDecimalCommas(result);
|
|
350
|
+
|
|
351
|
+
// 4. Posebni znaki + ( ) , ; * → presledki
|
|
352
|
+
result = replaceSpecialChars(result);
|
|
353
|
+
|
|
354
|
+
// 5. i.e. → ie
|
|
355
|
+
result = replaceIE(result);
|
|
356
|
+
|
|
357
|
+
// 6. tablete/tablet/tabl/tableta/tab → tbl
|
|
358
|
+
result = normalizeTablete(result);
|
|
359
|
+
|
|
360
|
+
// 6b. kapsul/kapsula/kaps/kap/caps → cap
|
|
361
|
+
result = normalizeKapsule(result);
|
|
362
|
+
|
|
363
|
+
// 6c. deci → dl
|
|
364
|
+
result = normalizeDeci(result);
|
|
365
|
+
|
|
366
|
+
// 6d. doza/doze → doz
|
|
367
|
+
result = normalizeDoz(result);
|
|
368
|
+
|
|
369
|
+
// 6d. tube/tubi/tuba → tub
|
|
370
|
+
result = normalizeTub(result);
|
|
371
|
+
|
|
372
|
+
// 6e. kosov/kosa/kosi → kos
|
|
373
|
+
result = normalizeKos(result);
|
|
374
|
+
|
|
375
|
+
// 6f. kom/komad/komada/komadi/komadov → kos
|
|
376
|
+
result = normalizeKom(result);
|
|
377
|
+
|
|
378
|
+
// 7. Odstrani pike za enotami
|
|
379
|
+
result = removeDotsAfterUnits(result);
|
|
380
|
+
|
|
381
|
+
// 8. Enota/enota brez presledkov
|
|
382
|
+
result = normalizeUnitSlash(result);
|
|
383
|
+
|
|
384
|
+
// 9. Številka enota brez presledkov
|
|
385
|
+
result = normalizeUnitSpaces(result);
|
|
386
|
+
|
|
387
|
+
// 10. Pike pred enoto → presledki
|
|
388
|
+
result = replaceDotsBeforeUnits(result);
|
|
389
|
+
|
|
390
|
+
// 10b. Pike pred presledkom → odstrani
|
|
391
|
+
result = removeDotsBeforeSpaces(result);
|
|
392
|
+
|
|
393
|
+
// 13. Pike za črkami → odstrani
|
|
394
|
+
result = removeDotsAfterLetters(result);
|
|
395
|
+
|
|
396
|
+
// 14. Pike med črkami → presledki
|
|
397
|
+
result = replaceDotsWithSpaces(result);
|
|
398
|
+
|
|
399
|
+
// 15. gr → g
|
|
400
|
+
result = normalizeGr(result);
|
|
401
|
+
|
|
402
|
+
// 12. Teže živali (decimalke se odstranijo znotraj funkcije)
|
|
403
|
+
result = normalizeWeightRanges(result);
|
|
404
|
+
|
|
405
|
+
// 17. Dodaj kg za vsako številko v teži
|
|
406
|
+
result = addKgToWeight(result);
|
|
407
|
+
|
|
408
|
+
// 15. Normaliziraj količine na koncu
|
|
409
|
+
result = normalizeTrailingQuantity(result);
|
|
410
|
+
|
|
411
|
+
// 16. Zamenjaj " / " s presledki
|
|
412
|
+
result = replaceSlashWithSpace(result);
|
|
413
|
+
|
|
414
|
+
// 16b. Odstrani / za presledkom
|
|
415
|
+
result = removeSlashAfterSpace(result);
|
|
416
|
+
|
|
417
|
+
// 17. Zamenjaj živalske vrste
|
|
418
|
+
result = normalizeAnimalSpecies(result);
|
|
419
|
+
|
|
420
|
+
// 18. Počisti odvečne presledke
|
|
421
|
+
result = result.replace(/\s+/g, " ").trim();
|
|
422
|
+
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Rezultat razčlenitve naziva zdravila
|
|
428
|
+
*/
|
|
429
|
+
export interface RazclenjeniNaziv {
|
|
430
|
+
izvorni_naziv: string;
|
|
431
|
+
normaliziran_naziv: string;
|
|
432
|
+
teza: string | null;
|
|
433
|
+
kolicina: string | null;
|
|
434
|
+
doze: string[];
|
|
435
|
+
besede: string[];
|
|
436
|
+
zivalskeVrste: string[];
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Vzorec za prepoznavanje doz (kombinacija številk, enot in "/")
|
|
441
|
+
* Primeri: 100mcg, 2mg/5ml, 2x3ml
|
|
442
|
+
*/
|
|
443
|
+
const DOZA_PATTERN = new RegExp(
|
|
444
|
+
`^(\\d+(?:\\.\\d+)?(?:x\\d+)?(?:${ENOTE.join("|")})(?:/(?:\\d+(?:\\.\\d+)?)?(?:${ENOTE.join("|")}))?)$`,
|
|
445
|
+
"i"
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Vzorec za prepoznavanje količine na koncu naziva
|
|
450
|
+
* Primeri: 7tbl, 10x5, 5*10, kos (brez mg, ml, g, kg, mcg, dl, ie)
|
|
451
|
+
*/
|
|
452
|
+
const KOLICINA_PATTERN = new RegExp(
|
|
453
|
+
`((?:\\d+(?:[x*]\\d+)?)?(?:${ENOTE_KOLICINE.join("|")})|\\d+[x*]\\d+)\\*?$`,
|
|
454
|
+
"i"
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Vzorec za prepoznavanje teže
|
|
459
|
+
* Primeri: 40kg-60kg, -40kg, 40kg-, 0.5kg
|
|
460
|
+
*/
|
|
461
|
+
const TEZA_PATTERN = /^-?\d+(?:\.\d+)?kg(?:-(?:\d+(?:\.\d+)?kg)?)?$/i;
|
|
462
|
+
|
|
463
|
+
// Izvozi tudi posamezne funkcije za testiranje
|
|
464
|
+
export {
|
|
465
|
+
toLowerCaseSL,
|
|
466
|
+
replaceSpecialChars,
|
|
467
|
+
replaceDecimalCommas,
|
|
468
|
+
replaceIE,
|
|
469
|
+
normalizeTablete,
|
|
470
|
+
normalizeKapsule,
|
|
471
|
+
normalizeDeci,
|
|
472
|
+
normalizeDoz,
|
|
473
|
+
normalizeTub,
|
|
474
|
+
normalizeKos,
|
|
475
|
+
normalizeKom,
|
|
476
|
+
removeDotsAfterUnits,
|
|
477
|
+
normalizeUnitSlash,
|
|
478
|
+
normalizeUnitSpaces,
|
|
479
|
+
replaceDotsBeforeUnits,
|
|
480
|
+
removeDotsBeforeSpaces,
|
|
481
|
+
removeDotsAfterLetters,
|
|
482
|
+
normalizeGr,
|
|
483
|
+
normalizeWeightRanges,
|
|
484
|
+
addKgToWeight,
|
|
485
|
+
removeZa,
|
|
486
|
+
normalizeTrailingQuantity,
|
|
487
|
+
replaceSlashWithSpace,
|
|
488
|
+
removeSlashAfterSpace,
|
|
489
|
+
normalizeAnimalSpecies,
|
|
490
|
+
DOZA_PATTERN,
|
|
491
|
+
KOLICINA_PATTERN,
|
|
492
|
+
TEZA_PATTERN,
|
|
493
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ZdraviloZUtemeljitvijo } from "../types/ZdraviloZUtemeljitvijo";
|
|
2
|
+
|
|
3
|
+
export function oblikujRezultatIskanja(rezultati: ZdraviloZUtemeljitvijo[]) {
|
|
4
|
+
const imamoNajboljsega = (rezultati?.length === 1)
|
|
5
|
+
||
|
|
6
|
+
(
|
|
7
|
+
(rezultati.length > 1)
|
|
8
|
+
&&
|
|
9
|
+
(rezultati[0].utemeljitev.ocena !== rezultati[1].utemeljitev.ocena)
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const najboljsi = (imamoNajboljsega && rezultati[0].zdravilo) || undefined;
|
|
13
|
+
const zadetki = rezultati?.map?.(r => ({ zdravilo: r.zdravilo, ocena: r.utemeljitev.ocena })) || [];
|
|
14
|
+
return { zadetki, najboljsi };
|
|
15
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ocena podobnosti med dvema razčlenjenima nazivoma zdravil
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { RazclenjeniNaziv } from "./normalizirajNaziv";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Utemeljitev ocene podobnosti
|
|
9
|
+
*/
|
|
10
|
+
export interface UtemeljitevOcene {
|
|
11
|
+
/** Skupna ocena podobnosti */
|
|
12
|
+
ocena: number;
|
|
13
|
+
/** Ocena ujemanja prvih štirih besed v obe smeri (prva: 500, druga: 300, tretja: 200, četrta: 100) */
|
|
14
|
+
ocenaPrvihBesed: number;
|
|
15
|
+
/** Ocena ujemanja velikosti (male/mali, srednje/srednji, velike/veliki) - 70 za vsako */
|
|
16
|
+
ocenaVelikosti: number;
|
|
17
|
+
/** Ocena ujemanja doz (0-200) */
|
|
18
|
+
ocenaDoze: number;
|
|
19
|
+
/** Ocena ujemanja živalskih vrst (0-200) */
|
|
20
|
+
ocenaZivalskihVrst: number;
|
|
21
|
+
/** Ocena ujemanja teže (0 ali 300) */
|
|
22
|
+
ocenaTeze: number;
|
|
23
|
+
/** Ocena ujemanja količine (0 ali 200) */
|
|
24
|
+
ocenaKolicine: number;
|
|
25
|
+
/** Ocena ujemanja besed (0-200) */
|
|
26
|
+
ocenaBesed: number;
|
|
27
|
+
/** Kazen za razliko v številu besed (-10 * razlika) */
|
|
28
|
+
steviloBesed: number;
|
|
29
|
+
/** uporavljena razčlemba */
|
|
30
|
+
razclembaRegistra: RazclenjeniNaziv
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Oceni podobnost med dvema razčlenjenima nazivoma
|
|
35
|
+
*
|
|
36
|
+
* @param razclembaVhoda - Razčlenjen vhodni naziv (iskalni niz)
|
|
37
|
+
* @param razclembaRegistra - Razčlenjen naziv iz registra zdravil
|
|
38
|
+
* @returns Utemeljitev z delnimi ocenami in skupno oceno
|
|
39
|
+
*/
|
|
40
|
+
export function oceniPodobnost(
|
|
41
|
+
razclembaVhoda: RazclenjeniNaziv,
|
|
42
|
+
razclembaRegistra: RazclenjeniNaziv
|
|
43
|
+
): UtemeljitevOcene {
|
|
44
|
+
// 1. Ocena prvih štirih besed
|
|
45
|
+
// Če se prve štiri besede zdravila iz registra pojavljajo v seznamu besed vhoda
|
|
46
|
+
let ocenaPrvihBesed = 0;
|
|
47
|
+
const tockeZaBesedo = [500, 300, 200, 100]; // prva, druga, tretja, četrta beseda
|
|
48
|
+
for (let i = 0; i < Math.min(4, razclembaRegistra.besede.length); i++) {
|
|
49
|
+
const besedaRegistra = razclembaRegistra.besede[i];
|
|
50
|
+
if (razclembaVhoda.besede.includes(besedaRegistra)) {
|
|
51
|
+
ocenaPrvihBesed += tockeZaBesedo[i];
|
|
52
|
+
} else {
|
|
53
|
+
// Delno ujemanje - preveri če je katera beseda iz vhoda prefiks besede iz registra ali obratno
|
|
54
|
+
for (const besedaVhoda of razclembaVhoda.besede) {
|
|
55
|
+
if (besedaVhoda.length >= 3 && (besedaRegistra.startsWith(besedaVhoda) || besedaVhoda.startsWith(besedaRegistra))) {
|
|
56
|
+
ocenaPrvihBesed += tockeZaBesedo[i] / 2;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 1b. Dodatna ocena: če se prve štiri besede vhoda pojavljajo v registru
|
|
64
|
+
// To zagotovi, da dobimo višjo oceno, če ima register besede, ki jih iščemo
|
|
65
|
+
for (let i = 0; i < Math.min(4, razclembaVhoda.besede.length); i++) {
|
|
66
|
+
const besedaVhoda = razclembaVhoda.besede[i];
|
|
67
|
+
if (razclembaRegistra.besede.includes(besedaVhoda)) {
|
|
68
|
+
ocenaPrvihBesed += tockeZaBesedo[i];
|
|
69
|
+
} else {
|
|
70
|
+
// Delno ujemanje - preveri če je katera beseda iz registra prefiks besede iz vhoda ali obratno
|
|
71
|
+
for (const besedaRegistra of razclembaRegistra.besede) {
|
|
72
|
+
if (besedaVhoda.length >= 3 && (besedaVhoda.startsWith(besedaRegistra) || besedaRegistra.startsWith(besedaVhoda))) {
|
|
73
|
+
ocenaPrvihBesed += tockeZaBesedo[i] / 2;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 2. Ocena velikosti (male/mali, srednje/srednji, velike/veliki, zelo)
|
|
81
|
+
const VELIKOSTI = ["male", "mali", "srednje", "srednji", "velike", "veliki", "zelo"];
|
|
82
|
+
let ocenaVelikosti = 0;
|
|
83
|
+
for (const velikost of VELIKOSTI) {
|
|
84
|
+
const vVhodu = razclembaVhoda.besede.includes(velikost);
|
|
85
|
+
const vRegistru = razclembaRegistra.besede.includes(velikost);
|
|
86
|
+
if (vVhodu && vRegistru) {
|
|
87
|
+
ocenaVelikosti += 70;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 3. Ocena doze
|
|
92
|
+
let ocenaDoze = 0;
|
|
93
|
+
if (razclembaRegistra.doze.length > 0) {
|
|
94
|
+
const tockeNaDozo = 200 / razclembaRegistra.doze.length;
|
|
95
|
+
const delneNaDozo = 100 / razclembaRegistra.doze.length;
|
|
96
|
+
|
|
97
|
+
for (const dozaVhoda of razclembaVhoda.doze) {
|
|
98
|
+
// Točno ujemanje
|
|
99
|
+
if (razclembaRegistra.doze.includes(dozaVhoda)) {
|
|
100
|
+
ocenaDoze += tockeNaDozo;
|
|
101
|
+
}
|
|
102
|
+
// Delno ujemanje - doza iz vhoda je začetek doze iz registra
|
|
103
|
+
else if (dozaVhoda.length > 3) {
|
|
104
|
+
for (const dozaRegistra of razclembaRegistra.doze) {
|
|
105
|
+
if (dozaRegistra.startsWith(dozaVhoda)) {
|
|
106
|
+
ocenaDoze += delneNaDozo;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Delno ujemanje - besede iz vhoda (številke brez enote) kot začetek doze iz registra
|
|
114
|
+
// Npr. "500" iz vhoda ujema "500mg" iz registra
|
|
115
|
+
for (const besedaVhoda of razclembaVhoda.besede) {
|
|
116
|
+
// Samo številke dolžine > 1
|
|
117
|
+
if (/^\d+$/.test(besedaVhoda) && besedaVhoda.length > 1) {
|
|
118
|
+
for (const dozaRegistra of razclembaRegistra.doze) {
|
|
119
|
+
if (dozaRegistra.startsWith(besedaVhoda)) {
|
|
120
|
+
ocenaDoze += delneNaDozo;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 3. Ocena živalskih vrst
|
|
129
|
+
let ocenaZivalskihVrst = 0;
|
|
130
|
+
if (razclembaRegistra.zivalskeVrste.length > 0) {
|
|
131
|
+
const tockeNaVrsto = 200 / razclembaRegistra.zivalskeVrste.length;
|
|
132
|
+
|
|
133
|
+
for (const vrstaRegistra of razclembaRegistra.zivalskeVrste) {
|
|
134
|
+
if (razclembaVhoda.zivalskeVrste.includes(vrstaRegistra)) {
|
|
135
|
+
ocenaZivalskihVrst += tockeNaVrsto;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 4. Ocena teže
|
|
141
|
+
let ocenaTeze = 0;
|
|
142
|
+
if (razclembaRegistra.teza && razclembaVhoda.teza) {
|
|
143
|
+
if (razclembaRegistra.teza === razclembaVhoda.teza) {
|
|
144
|
+
ocenaTeze = 300;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 5. Ocena količine
|
|
149
|
+
let ocenaKolicine = 0;
|
|
150
|
+
if (razclembaRegistra.kolicina && razclembaVhoda.kolicina) {
|
|
151
|
+
if (razclembaRegistra.kolicina === razclembaVhoda.kolicina) {
|
|
152
|
+
ocenaKolicine = 200;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 7. Ocena besed
|
|
157
|
+
let ocenaBesed = 0;
|
|
158
|
+
for (const besedaVhoda of razclembaVhoda.besede) {
|
|
159
|
+
if (razclembaRegistra.besede.includes(besedaVhoda)) {
|
|
160
|
+
ocenaBesed += 10 * besedaVhoda.length;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Omejitev na največ 200
|
|
164
|
+
ocenaBesed = Math.min(ocenaBesed, 200);
|
|
165
|
+
|
|
166
|
+
// 8. Kazen za razliko v številu besed
|
|
167
|
+
const razlikaBesed = Math.abs(razclembaVhoda.besede.length - razclembaRegistra.besede.length);
|
|
168
|
+
const steviloBesed = -10 * razlikaBesed;
|
|
169
|
+
|
|
170
|
+
// Skupna ocena
|
|
171
|
+
const ocena =
|
|
172
|
+
ocenaPrvihBesed +
|
|
173
|
+
ocenaVelikosti +
|
|
174
|
+
ocenaDoze +
|
|
175
|
+
ocenaZivalskihVrst +
|
|
176
|
+
ocenaTeze +
|
|
177
|
+
ocenaKolicine +
|
|
178
|
+
ocenaBesed +
|
|
179
|
+
steviloBesed;
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
ocena,
|
|
183
|
+
ocenaPrvihBesed,
|
|
184
|
+
ocenaVelikosti,
|
|
185
|
+
ocenaDoze,
|
|
186
|
+
ocenaZivalskihVrst,
|
|
187
|
+
ocenaTeze,
|
|
188
|
+
ocenaKolicine,
|
|
189
|
+
ocenaBesed,
|
|
190
|
+
steviloBesed,
|
|
191
|
+
razclembaRegistra,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|