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.
Files changed (84) hide show
  1. package/.claude/settings.local.json +17 -0
  2. package/CLAUDE.md +82 -0
  3. package/LICENSE.md +16 -0
  4. package/README.md +376 -0
  5. package/a.txt +1643 -0
  6. package/bun.lock +197 -0
  7. package/dist/atcvet/opisATCvetKode.d.ts +23 -0
  8. package/dist/atcvet/podatkiATCvetKode.d.ts +20 -0
  9. package/dist/atcvet/pomeniNivojevATCvet.d.ts +1 -0
  10. package/dist/atcvet/types/AtcvetFile.d.ts +19 -0
  11. package/dist/generated/AtcVet.d.ts +9 -0
  12. package/dist/generated/RegisterZdravil.d.ts +8 -0
  13. package/dist/generated/seznamZdravil.d.ts +8 -0
  14. package/dist/index.d.ts +244 -0
  15. package/dist/index.js +141786 -0
  16. package/dist/register/MIN_OCENA_PODOBNOSTI.d.ts +2 -0
  17. package/dist/register/helper/normalizirajNaziv.d.ts +176 -0
  18. package/dist/register/helper/oblikujRezultatIskanja.d.ts +8 -0
  19. package/dist/register/helper/oceniPodobnost.d.ts +37 -0
  20. package/dist/register/helper/poisciZivalskoVrsto.d.ts +33 -0
  21. package/dist/register/helper/razcleniNaziv.d.ts +2 -0
  22. package/dist/register/podobnaZdravilaPoATC.d.ts +16 -0
  23. package/dist/register/podobnaZdravilaPoUcinkovinah.d.ts +18 -0
  24. package/dist/register/registerZdravil.d.ts +9 -0
  25. package/dist/register/types/KarencaZdravila.d.ts +24 -0
  26. package/dist/register/types/PotUporabeZdravila.d.ts +21 -0
  27. package/dist/register/types/RazclembaZdravila.d.ts +9 -0
  28. package/dist/register/types/RegisterZdravil.d.ts +2 -0
  29. package/dist/register/types/UcinkovinaZdravila.d.ts +20 -0
  30. package/dist/register/types/Zdravilo.d.ts +65 -0
  31. package/dist/register/types/ZdraviloZUtemeljitvijo.d.ts +9 -0
  32. package/dist/register/types/ZivalskeVrste.d.ts +158 -0
  33. package/dist/register/uganiZdravilo.d.ts +43 -0
  34. package/dist/register/zdravilaZaAtcVetKodo.d.ts +8 -0
  35. package/dist/register/zdraviloJeVakcinaZa.d.ts +18 -0
  36. package/docs/vakcine.md +195 -0
  37. package/package.json +39 -0
  38. package/src/atcvet/CLAUDE.md +18 -0
  39. package/src/atcvet/downloadLatestAtcvetPdf.ts +107 -0
  40. package/src/atcvet/opisATCvetKode.ts +116 -0
  41. package/src/atcvet/parseAtcvetPdf.ts +215 -0
  42. package/src/atcvet/podatkiATCvetKode.ts +34 -0
  43. package/src/atcvet/pomeniNivojevATCvet.ts +8 -0
  44. package/src/atcvet/types/AtcvetFile.ts +22 -0
  45. package/src/generate.ts +111 -0
  46. package/src/generated/AtcVet.ts +56704 -0
  47. package/src/generated/seznamZdravil.ts +44833 -0
  48. package/src/importParseAndBuildAll.ts +97 -0
  49. package/src/index.ts +289 -0
  50. package/src/interactive.ts +428 -0
  51. package/src/register/CLAUDE.md +230 -0
  52. package/src/register/MIN_OCENA_PODOBNOSTI.ts +3 -0
  53. package/src/register/downloadRegister.ts +148 -0
  54. package/src/register/helper/analizaVakcin.ts +90 -0
  55. package/src/register/helper/checkVrste.ts +72 -0
  56. package/src/register/helper/hashString.ts +27 -0
  57. package/src/register/helper/normalizirajNaziv.ts +493 -0
  58. package/src/register/helper/oblikujRezultatIskanja.ts +15 -0
  59. package/src/register/helper/oceniPodobnost.ts +194 -0
  60. package/src/register/helper/poisciZivalskoVrsto.ts +100 -0
  61. package/src/register/helper/razcleniNaziv.ts +105 -0
  62. package/src/register/helper/testNormalizacije.ts +89 -0
  63. package/src/register/helper/testPodobnosti.ts +238 -0
  64. package/src/register/helper/testVakcin.ts +103 -0
  65. package/src/register/parseRegister.ts +464 -0
  66. package/src/register/podobnaZdravilaPoATC.ts +71 -0
  67. package/src/register/podobnaZdravilaPoUcinkovinah.ts +136 -0
  68. package/src/register/registerZdravil.ts +22 -0
  69. package/src/register/stats.ts +114 -0
  70. package/src/register/types/KarencaZdravila.ts +26 -0
  71. package/src/register/types/PotUporabeZdravila.ts +21 -0
  72. package/src/register/types/RazclembaZdravila.ts +10 -0
  73. package/src/register/types/RegisterRaw.ts +23 -0
  74. package/src/register/types/RegisterZdravil.ts +3 -0
  75. package/src/register/types/UcinkovinaZdravila.ts +21 -0
  76. package/src/register/types/Zdravilo.ts +84 -0
  77. package/src/register/types/ZdraviloZUtemeljitvijo.ts +11 -0
  78. package/src/register/types/ZivalskeVrste.ts +7 -0
  79. package/src/register/uganiZdravilo.ts +142 -0
  80. package/src/register/zdravilaZaAtcVetKodo.ts +28 -0
  81. package/src/register/zdraviloJeVakcinaZa.ts +202 -0
  82. package/src/test/testPodobnosti.test.ts +126 -0
  83. package/src/test/zdravila.json +38693 -0
  84. 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
+