1/***************************************************************************************** 2 * Firma: Hehner Reus Systems GmbH 3 * Projekt: com.cerno.basis 4 * Datei: String.js 5 * Erstellung: 29.07.2019 6 * Verwendung: Toolklasse für Javascript-Funktionen rund um das globale String-Objekt. 7 * 8 * $Id: String.js,v 1.29 2025/06/05 09:17:10 lpo Exp $ 9 *****************************************************************************************/ 10 11/** 12 * Erweiterung des String-Objektes: Ersetzt alle Vorkommnisse eines regulären Ausdruckes in einer 13 * gegebenen Zeichenkette durch eine weitere, übergebene Zeichenkette. 14 * 15 * @param search Der zu suchende reguläre Ausdruck. 16 * @param replacement Die Zeichenkette, die das Auftreten des regulären Ausdrucks ersetzt. 17 * @return Die bearbeitete Zeichenkette oder die ursprüngliche Zeichenkette im Fehlerfall. 18 * 19 * Bemerkung: Ab ECMAScript 6 gibt es diese Funktion auch fest im Repertoir des String-Objektes. 20 */ 21if (typeof String.prototype.replaceAll !== 'function') 22{ 23 String.prototype.replaceAll = function(search, replacement) 24 { 25 try 26 { 27 var target = this; 28 return target.split(search).join(replacement); 29 } 30 catch (e) 31 { 32 if (typeof(HRLogError) === 'function') 33 HRLogError(e); 34 } 35 return this; 36 } 37} 38 39/** 40 * Erweiterung des String-Objektes: Gibt an, ob eine Zeichenkette mit einem 41 * gegebenen Ausdruck endet oder nicht. 42 * 43 * @param suffix Der zu prüfende Ausdruck 44 * @return true, falls die Zeichenkette mit dem gegebenen Ausdruck endet. 45 * 46 * Bemerkung: Ab ECMAScript 6 gibt es diese Funktion auch fest im Repertoir des String-Objektes. 47 */ 48if (typeof String.prototype.endsWith !== 'function') 49{ 50 String.prototype.endsWith = function(suffix) 51 { 52 try 53 { 54 return this.indexOf(suffix, this.length - suffix.length) !== -1; 55 } 56 catch (e) 57 { 58 if (typeof(HRLogError) === 'function') 59 HRLogError(e); 60 } 61 return false; 62 } 63} 64 65/** 66 * Erweiterung des String-Objektes: Gibt an, ob eine Zeichenkette mit einem 67 * gegebenen Ausdruck beginnt oder nicht. 68 * 69 * @param prefix Der zu prüfende Ausdruck 70 * @return true, falls die Zeichenkette mit dem gegebenen Ausdruck beginnt. Im Fehlerfall false. 71 * 72 * Bemerkung: Ab ECMAScript 6 gibt es diese Funktion auch fest im Repertoir des String-Objektes. 73 */ 74if (typeof String.prototype.startsWith !== 'function') 75{ 76 String.prototype.startsWith = function(prefix) 77 { 78 try 79 { 80 // "lastIndexOf" durchsucht den String normalerweise beginnend beim letzten Zeichen, mit dem Startindex "0" 81 // jedoch wird nur ein einziger Vergleich mit dem Ausdruck gemacht => sehr effizient! 82 return this.lastIndexOf(prefix, 0) === 0; 83 } 84 catch (e) 85 { 86 if (typeof(HRLogError) === 'function') 87 HRLogError(e); 88 } 89 90 return false; 91 } 92} 93 94/** 95 * Erweiterung des String-Objektes: Prüft, ob eine Zeichenkette leer ist. 96 * 97 * @return true, falls die Zeichenkette leer ist oder ein Fehler aufgetreten ist. 98 * 99 * Bemerkung: Ab ECMAScript 6 gibt es diese Funktion auch fest im Repertoir des String-Objektes. 100 */ 101if (typeof String.prototype.isEmpty !== 'function') 102{ 103 String.prototype.isEmpty = function() 104 { 105 try 106 { 107 return this.length <= 0; 108 } 109 catch (e) 110 { 111 if (typeof(HRLogError) === 'function') 112 HRLogError(e); 113 } 114 return true; 115 } 116} 117 118/** 119 * Erweiterung des String-Objektes: Prüft, ob eine Zeichenkette eine gegebene Zeichenkette enthält. 120 * 121 * @param str Die Zeichenkette, die geprüft werden soll. 122 * @return true, falls die Zeichenkette die angegebene Zeichenkette enthält.. 123 */ 124if (typeof String.prototype.contains !== 'function') 125{ 126 String.prototype.contains = function(str) 127 { 128 try 129 { 130 return this.indexOf(str) >= 0; 131 } 132 catch (e) 133 { 134 if (typeof(HRLogError) === 'function') 135 HRLogError(e); 136 } 137 return true; 138 } 139} 140 141/** 142 * Erweiterung des String-Objektes: Case-insensitive Prüfung auf Gleichheit. 143 * 144 * @param str Die auf Gleichheit zu prüfende Zeichenkette. 145 * @return true, falls die Zeichenkette bis auf Groß- und Kleinschreibung identisch 146 * sind. Falls ein Fehler auftritt, wird false zurückgegeben. 147 */ 148if (typeof String.prototype.equalsIgnoreCase !== 'function') 149{ 150 String.prototype.equalsIgnoreCase = function(str) 151 {
152 try 153 { 154 if (typeof(str) === "string") 155 return (this.toUpperCase() === str.toUpperCase()); 156 } 157 catch (e) 158 { 159 if (typeof(HRLogError) === 'function') 160 HRLogError(e); 161 } 162 163 return false; 164 } 165} 166 167/** 168 * Funktion zum Kürzen von HTML-Inhalten. 169 * 170 * @param maxLength Länge des neuen Textes. 171 * @return Gibt den gekürzten Text zurück. 172 */ 173if (typeof String.prototype.truncate !== 'function') 174{ 175 String.prototype.truncate = function(maxLength) 176 { 177 try 178 { 179 if (this) 180 { 181 // Prüfen, ob der Textinhalt (ohne die HTML-Tags) überhaupt gekürzt werden muss. 182 const el = document.createElement("div"); 183 el.innerHTML = this.trim(); 184 const match = el.textContent.trim().length; 185 el.remove(); 186 187 // Kürzen, wenn der Textinhalt des HTMLs zu groß ist. 188 return match ? HRTextClipper.clip(this, maxLength, {html: true}) : this; 189 } 190 } 191 catch (e) 192 { 193 if (typeof(HRLogError) === 'function') 194 HRLogError(e); 195 } 196 return null; 197 } 198} 199 200/** 201 * Funktion zum Hashen, funktioniert genauso wie das Pendant in Java. 202 * 203 * @return ein Hashcode. 204 */ 205if (typeof String.prototype.hashCode !== 'function') 206{ 207 String.prototype.hashCode = function() 208 { 209 let hash = 0, i, c; 210 211 if (this.length === 0) 212 return hash; 213 214 for (i = 0; i < this.length; i++) 215 { 216 c = this.charCodeAt(i); 217 hash = ((hash << 5) - hash) + c; 218 hash |= 0; // in eine 32-bit-Zahl konvertieren. 219 } 220 221 return hash; 222 } 223} 224 225/** 226 * Funktion zum Zählen von Wörtern in einer gegebenen Zeichenkette. 227 * 228 * @return Die Anzahl der Wörter. Falls ein Leerstring oder eine nicht gültige 229 * Zeichenkette übergeben wird, wird 0 zurückgegeben. 230 */ 231if (typeof String.prototype.countWords !== 'function') 232{ 233 String.prototype.countWords = function() 234 { 235 try 236 { 237 if (this) 238 { 239 if (!this.isEmpty()) 240 return this.trim().split(/\s+/).length; 241 } 242 } 243 catch (e) 244 { 245 if (typeof(HRLogError) === 'function') 246 HRLogError(e); 247 } 248 249 return 0; 250 }; 251} 252 253/** 254 * Wandelt alle nicht-ISO-Zeichen in Zeichenreferenzen um. 255 * 256 * @param blacklist Ein Blacklist-Array mit Zeichen, die von der 257 * Umwandelung ausgeschlossen werden sollen. 258 * @param onlyNonIso Schalter, damit nur die Nicht-Iso-Zeichen in Zeichenreferenzen kodiert werden. 259 * In diesem Fall wird geprüft, ob das Zeichen außerhalb der ISO-8859-1-Range (0-255) liegt. 260 * @return Die bearbeitete Zeichenkette. 261 */ 262if (typeof String.prototype.encodeToNumericCharReferences !== 'function') 263{ 264 String.prototype.encodeToNumericCharReferences = function(blacklist, onlyNonIso) 265 { 266 try 267 { 268 if (this) 269 { 270 return this.split(/(?:)/u).map(char => { 271 if (blacklist && blacklist.includes(char)) 272 return char; 273 else if (!onlyNonIso || char.codePointAt(0) > 255) 274 return '&#' + char.codePointAt(0) + ';'; 275 else 276 return char; 277 }).join(''); 278 } 279 } 280 catch (e) 281 { 282 if (typeof(HRLogError) === 'function') 283 HRLogError(e); 284 } 285 286 return this; 287 }; 288} 289 290/** 291 * Wandelt alle nicht-ISO-Zeichen in HTML-Entitäten um. 292 * 293 * @param blacklist Ein Blacklist-Array mit Zeichen, die von der 294 * Umwandelung ausgeschlossen werden sollen. 295 * @return Die bearbeitete Zeichenkette. 296 */ 297if (typeof String.prototype.encodeToHtmlEntities !== 'function') 298{ 299 String.prototype.encodeToHtmlEntities = function(blacklist) 300 { 301 try 302 { 303 if (this) 304 { 305 return this.split('').map(char => { 306 if (blacklist && blacklist.includes(char)) 307 return char; 308 else 309 { 310 const code = char.charCodeAt(0); 311 312 // Nur ersetzen, wenn außerhalb ASCII oder HTML-reserviert. 313 if (code > 127 || ['&', '<', '>', '"', "'"].includes(char)) 314 return `&#${code};`; 315 316 return char; 317 } 318 }).join(''); 319 } 320 } 321 catch (e) 322 { 323 if (typeof(HRLogError) === 'function') 324 HRLogError(e); 325 } 326 327 return this; 328 }; 329} 330 331/** 332 * Wandelt alle HTML-Entitäten zurück in die entsprechenden Zeichen um. 333 * 334 * @return Die bearbeitete Zeichenkette. 335 */ 336if (typeof String.prototype.decodeFromHtmlEntities !== 'function') 337{ 338 String.prototype.decodeFromHtmlEntities = function() 339 {
340 try 341 { 342 if (this) 343 { 344 const txt = document.createElement("textarea"); 345 txt.innerHTML = this; 346 return txt.value; 347 } 348 } 349 catch (e) 350 { 351 if (typeof(HRLogError) === 'function') 352 HRLogError(e); 353 } 354 355 return this; 356 }; 357} 358 359/** 360 * Entfernt die HTML-Entitäten einer Zeichenkette. 361 * 362 * @return Die bearbeitete Zeichenkette. 363 */ 364if (typeof String.prototype.removeHtmlTags !== 'function') 365{ 366 String.prototype.removeHtmlTags = function() 367 { 368 try 369 { 370 if (this) 371 { 372 const parser = new DOMParser(); 373 const doc = parser.parseFromString(this, 'text/html'); 374 const textContent = doc.body.textContent || ''; 375 return new DOMParser().parseFromString(textContent, 'text/html').documentElement.textContent; 376 } 377 } 378 catch (e) 379 { 380 if (typeof(HRLogError) === 'function') 381 HRLogError(e); 382 } 383 384 return this; 385 }; 386} 387 388/** 389 * Dient dem Vorbeugen von Script-Injections (XSS-Attacken). Es werden HTML-spezifische Zeichen 390 * durch ihre URL-Code-Varianten ersetzt.Es soll verhindert werden, dass HTML durch die Verwendung 391 * von innerHTML in die Seiten eingebaut werden kann. Das ist bspw. beim Aufrufprotokoll 392 * interessant, da dort URL-Parameter auseinandergenommen werden und durch innerHTML in die Seite 393 * eingebaut werden. 394 * 395 * @return Die bearbeitete Zeichenkette. 396 */ 397if (typeof String.prototype.sanitizeURLParameter !== 'function') 398{ 399 String.prototype.sanitizeURLParameter = function() 400 { 401 try 402 { 403 if (this) 404 { 405 return encodeURIComponent(this) 406 .replace(/'/g, '%27') // Ersetzt "'" 407 .replace(/\(/g, '%28') // Ersetzt '(' 408 .replace(/\)/g, '%29'); // Ersetzt ')' 409 } 410 } 411 catch (e) 412 { 413 if (typeof(HRLogError) === 'function') 414 HRLogError(e); 415 } 416 417 return this; 418 }; 419} 420 421/** 422 * Prüft, ob die Zeichenkette ein valider CSS-Klassenname ist. Diese darf beinhalten: 423 * <ul> 424 * <li>Buchstaben (a-z, A-Z)</li> 425 * <li>Ziffern (0-9)</li> 426 * <li>Bindestrich (-) und Unterstrich (_)</li> 427 * <li>Unicode-Zeichen, sofern sie korrekt codiert sind</li> 428 * </ul> 429 * Ein valider Name einer CSS-Klasse muss zudem mit einem Buchstaben oder einem Bindestrich beginnen. Alle anderen 430 * Zeichen sind dort nicht zulässig. 431 * 432 * @return true, falls die Zeichenkette die obigen Bedingungen erfüllt. 433 */ 434if (typeof String.prototype.isValidCSSName !== 'function') 435{ 436 String.prototype.isValidCSSName = function() 437 { 438 try 439 { 440 if (!this) 441 return false; 442 443 const regexClassInput = /^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/; 444 445 return regexClassInput.test(this); 446 } 447 catch (e) 448 { 449 if (typeof(HRLogError) === 'function') 450 HRLogError(e); 451 } 452 453 return false; 454 }; 455} 456 457/** 458 * Prüft, ob die Zeichenkette ein valider JSON-Schlüssel ist. Die Regeln sind: 459 * <ul> 460 * <li>Muss mit einem Buchstabe oder _ oder : beginnen.</li> 461 * <li>Darf keine Leerzeichen, Steuerzeichen oder reservierte Zeichen wie <, >, & enthalten.</li> 462 * <li>Darf nicht mit "xml" (case-insensitive) beginnen.</li> 463 * </ul> 464 * 465 * @return true, falls die Zeichenkette die obigen Bedingungen erfüllt. 466 */ 467if (typeof String.prototype.isValidXMLName !== 'function') 468{ 469 String.prototype.isValidXMLName = function() 470 { 471 try 472 { 473 if (!this) 474 return false; 475 476 const xmlNameStartChar = /^[A-Za-z_][A-Za-z0-9._-]*$/; 477 const startsWithXML = /^xml/i; 478 479 return xmlNameStartChar.test(this) && !startsWithXML.test(name); 480 } 481 catch (e) 482 { 483 if (typeof(HRLogError) === 'function') 484 HRLogError(e); 485 } 486 487 return false; 488 }; 489}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.