{"id":36,"date":"2025-10-16T11:29:00","date_gmt":"2025-10-16T09:29:00","guid":{"rendered":"https:\/\/romejs.dev\/2025\/10\/16\/javascript-substring\/"},"modified":"2026-01-27T12:41:16","modified_gmt":"2026-01-27T11:41:16","slug":"javascript-substring","status":"publish","type":"post","link":"https:\/\/romejs.dev\/javascript-substring\/","title":{"rendered":"JavaScript substring richtig einsetzen: Syntax, Unterschiede, Praxisnutzen und typische Fallen"},"content":{"rendered":"<p><strong>substring()<\/strong> ist eine der meistgenutzten String-Methoden in <a href=\"https:\/\/romejs.dev\/\">JavaScript<\/a>. Sie extrahiert Teile eines Textes, ohne das Original zu ver\u00e4ndern. In diesem Leitfaden zeige ich dir pr\u00e4zise, wie substring() funktioniert, worin es sich von <em>slice()<\/em> und <em>substr()<\/em> unterscheidet, welche Edge-Cases dich in der Praxis erwarten, wie du Unicode- und Emoji-Fallen meidest, und welche Best Practices sich bew\u00e4hrt haben.<\/p>\n<hr\/>\n<h2>Was substring() konkret macht<\/h2>\n<p>Mit <code>substring(start, end?)<\/code> holst du dir die Zeichen von <code>start<\/code> bis <em>exklusiv<\/em> <code>end<\/code>. L\u00e4sst du <code>end<\/code> weg, geht es bis zum Ende des Strings. Der urspr\u00fcngliche String bleibt unver\u00e4ndert.<\/p>\n<pre><code class=\"language-js\">const s = \"Mozilla\";\ns.substring(1, 3);   \/\/ \"oz\"  (Index 1 und 2)\ns.substring(3);      \/\/ \"illa\" (ab Index 3 bis Ende)\ns.substring(0, 0);   \/\/ \"\" (leer)\n<\/code><\/pre>\n<blockquote>\n<p><strong>Merksatz:<\/strong> substring() nutzt 0-basierte Indizes und schlie\u00dft den Endindex nicht ein.<\/p>\n<\/blockquote>\n<hr\/>\n<h2>Syntax, Parameter und Typumwandlungen<\/h2>\n<table>\n<thead>\n<tr>\n<th>Parameter<\/th>\n<th>Typ<\/th>\n<th>Bedeutung<\/th>\n<th>Besonderheiten<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>start<\/td>\n<td>Number<\/td>\n<td>Index des ersten einzuschlie\u00dfenden Zeichens<\/td>\n<td>0-basiert; negative Werte werden auf 0 geklemmt<\/td>\n<\/tr>\n<tr>\n<td>end (optional)<\/td>\n<td>Number<\/td>\n<td>Index des <em>ersten auszuschlie\u00dfenden<\/em> Zeichens<\/td>\n<td>Fehlt end, geht die Extraktion bis zum Ende<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<ul>\n<li><strong>Clamping:<\/strong> Werte &lt; 0 werden zu 0; Werte &gt; L\u00e4nge werden zur Stringl\u00e4nge.<\/li>\n<li><strong>Vertauschen:<\/strong> Ist <code>start &gt; end<\/code>, werden die Werte automatisch getauscht.<\/li>\n<li><strong>NaN\/Infinity:<\/strong> <code>NaN<\/code> wird wie 0 behandelt, <code>Infinity<\/code> wie Stringl\u00e4nge.<\/li>\n<li><strong>Flie\u00dfkommazahlen:<\/strong> werden intern auf Integer <em>abgeschnitten<\/em> (Trunkierung Richtung 0).<\/li>\n<li><strong>Typ-Coercion:<\/strong> \u00dcbergibst du z. B. <code>\"5\"<\/code>, wird es zu <code>5<\/code> konvertiert.<\/li>\n<\/ul>\n<pre><code class=\"language-js\">const str = \"ABCDE\";\nstr.substring(-3, 2);     \/\/ \"AB\" (start =&gt; 0, end =&gt; 2)\nstr.substring(4, 2);      \/\/ \"CD\" (start &gt; end =&gt; swap)\nstr.substring(2, 2);      \/\/ \"\"\nstr.substring(2, 99);     \/\/ \"CDE\" (end wird auf L\u00e4nge geklemmt)\nstr.substring(2.9, 4.2);  \/\/ \"CD\" (2.9 =&gt; 2, 4.2 =&gt; 4)\n<\/code><\/pre>\n<hr\/>\n<p><img alt=\"javascript substring\" decoding=\"async\" src=\"https:\/\/romejs.dev\/wp-content\/uploads\/2025\/10\/javascript_substring_ins3.jpg\" style=\"display:block; margin:20px auto; max-width:80%; height:auto;\"\/><\/p>\n<h2>substring() vs slice() vs substr(): Die Unterschiede auf einen Blick<\/h2>\n<table>\n<thead>\n<tr>\n<th>Merkmal<\/th>\n<th>substring(start, end?)<\/th>\n<th>slice(start, end?)<\/th>\n<th>substr(start, length?)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>End-Argument<\/td>\n<td>exklusive Endposition<\/td>\n<td>exklusive Endposition<\/td>\n<td>Anzahl Zeichen<\/td>\n<\/tr>\n<tr>\n<td>Negative Indizes<\/td>\n<td>nicht unterst\u00fctzt (geklammert zu 0)<\/td>\n<td>unterst\u00fctzt (z\u00e4hlt vom Ende)<\/td>\n<td>Start negativ = vom Ende<\/td>\n<\/tr>\n<tr>\n<td>Start &gt; End<\/td>\n<td>Werte werden getauscht<\/td>\n<td>gibt \u201e\u201c (leer) zur\u00fcck<\/td>\n<td>n\/a<\/td>\n<\/tr>\n<tr>\n<td>Status<\/td>\n<td>Standard<\/td>\n<td>Standard<\/td>\n<td>Legacy\/Veraltet, nicht empfohlen<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Codebeispiele, die die Unterschiede verdeutlichen:<\/p>\n<pre><code class=\"language-js\">const s = \"Mozilla\";\n\n\/\/ Negative Indizes\ns.substring(-5);  \/\/ \"Mozilla\" (Start =&gt; 0, also gesamter String)\ns.slice(-5);      \/\/ \"zilla\"   (die letzten 5 Zeichen)\ns.substr(-5, 3);  \/\/ \"zil\"     (Start 5 vor Ende, dann 3 Zeichen)\n\n\/\/ Vertauschte Indizes\ns.substring(5, 2); \/\/ \"zil\" (swap zu (2,5))\ns.slice(5, 2);     \/\/ \"\"    (kein Swap)\n\n\/\/ L\u00e4nge vs Endindex\n\"Hello, World!\".substring(7, 12); \/\/ \"World\"\n\"Hello, World!\".substr(7, 5);     \/\/ \"World\"\n\"Hello, World!\".slice(7, 12);     \/\/ \"World\"\n<\/code><\/pre>\n<blockquote>\n<p><strong>Empfehlung:<\/strong> Nutze <em>substring()<\/em>, wenn du bewusst mit Start-\/Endpositionen arbeitest und kein negatives Indexing brauchst. Nutze <em>slice()<\/em>, wenn negative Indizes relevant sind oder du leeres Ergebnis bei vertauschten Parametern bevorzugst. <em>substr()<\/em> gilt als legacy und sollte vermieden werden.<\/p>\n<\/blockquote>\n<hr\/>\n<h2>Praxisnahe Anwendungsf\u00e4lle<\/h2>\n<h3>Dom\u00e4ne aus E-Mail extrahieren<\/h3>\n<pre><code class=\"language-js\">const email = \"user@example.com\";\nconst at = email.indexOf(\"@\");\nconst domain = at !== -1 ? email.substring(at + 1) : \"\";\n\/\/ \"example.com\"\n<\/code><\/pre>\n<h3>Dateiendung ermitteln<\/h3>\n<pre><code class=\"language-js\">const filename = \"report.final.v3.pdf\";\nconst dot = filename.lastIndexOf(\".\");\nconst ext = dot !== -1 ? filename.substring(dot + 1) : \"\";\n\/\/ \"pdf\"\n<\/code><\/pre>\n<h3>Letzte n Zeichen (z. B. Maskierung)<\/h3>\n<pre><code class=\"language-js\">const iban = \"DE12345678901234567890\";\nconst last4 = iban.substring(iban.length - 4); \/\/ \"7890\"\nconst masked = \"**** **** **** **** \" + last4;\n\/\/ \"**** **** **** **** 7890\"\n<\/code><\/pre>\n<h3>Erstes Wort oder Prefix extrahieren<\/h3>\n<pre><code class=\"language-js\">const title = \"<a href=\"https:\/\/romejs.dev\/was-ist-javascript\/\">ECMAScript<\/a> Guide\";\nconst space = title.indexOf(\" \");\nconst firstWord = space === -1 ? title : title.substring(0, space);\n\/\/ \"ECMAScript\"\n<\/code><\/pre>\n<h3>Pfadteile aus URL ziehen (ohne URL API)<\/h3>\n<pre><code class=\"language-js\">const url = \"https:\/\/example.com\/blog\/articles\/123?ref=home\";\nconst protoSep = \":\/\/\";\nconst schemaEnd = url.indexOf(protoSep);\nconst afterSchema = schemaEnd !== -1 ? url.substring(schemaEnd + protoSep.length) : url;\n\/\/ \"example.com\/blog\/articles\/123?ref=home\"\nconst pathStart = afterSchema.indexOf(\"\/\");\nconst host = pathStart !== -1 ? afterSchema.substring(0, pathStart) : afterSchema;\n\/\/ \"example.com\"\nconst pathWithQuery = pathStart !== -1 ? afterSchema.substring(pathStart) : \"\";\n\/\/ \"\/blog\/articles\/123?ref=home\"\n<\/code><\/pre>\n<h3>Normierung: Trimmen eines Slugs auf feste L\u00e4nge<\/h3>\n<pre><code class=\"language-js\">function normalizeSlug(s, max = 50) {\n  const clean = s.toLowerCase().replace(\/\\s+\/g, \"-\").replace(\/[^a-z0-9\\-]\/g, \"\");\n  return clean.length &gt; max ? clean.substring(0, max) : clean;\n}\n<\/code><\/pre>\n<hr\/>\n<h2>Unicode, Emojis und zusammengesetzte Zeichen: das gro\u00dfe Missverst\u00e4ndnis<\/h2>\n<p><strong>Wichtig:<\/strong> JavaScript-Strings sind UTF-16 sequenzen. substring(), slice() und Co. arbeiten auf <em>Code Units<\/em>, nicht auf <em>Grapheme-Clusters<\/em>. Dadurch kannst du Emojis und zusammengesetzte Zeichen unabsichtlich \u201ezers\u00e4gen\u201c.<\/p>\n<p>Beispiel mit Emoji:<\/p>\n<pre><code class=\"language-js\">const emoji = \"A\ud83d\ude0aB\";\nemoji.length;              \/\/ 4 (\ud83d\ude0a besteht aus 2 UTF-16 Code Units)\nemoji.substring(1, 2);     \/\/ liefert nur die erste Code Unit des Emojis =&gt; kaputter String\n<\/code><\/pre>\n<p><strong>So machst du es richtig:<\/strong><\/p>\n<ul>\n<li><strong>Codepoint-sicher<\/strong> via Iteration: <code>Array.from(str)<\/code> nutzt den String-Iterator (iteriert \u00fcber Unicode-Codepunkte).<\/li>\n<li><strong>Graphem-sicher<\/strong>: <code>Intl.Segmenter<\/code> (moderne Engines) oder Bibliotheken wie <em>grapheme-splitter<\/em>.<\/li>\n<\/ul>\n<pre><code class=\"language-js\">\/\/ Codepoint-sicher\nfunction cpSubstring(str, start, end = Infinity) {\n  const arr = Array.from(str); \/\/ iteriert \u00fcber Codepoints\n  return arr.slice(start, end).join(\"\");\n}\n\ncpSubstring(\"A\ud83d\ude0aB\", 0, 2); \/\/ \"A\ud83d\ude0a\"\n\n\/\/ Graphem-sicher (z. B. f\u00fcr zusammengesetzte Emojis\/Flags\/Skintones)\nfunction graphemeSplit(str) {\n  if (typeof Intl !== \"undefined\" &amp;&amp; Intl.Segmenter) {\n    const seg = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n    return Array.from(seg.segment(str), s =&gt; s.segment);\n  }\n  \/\/ Fallback (vereinfachend): Codepoint-Split\n  return Array.from(str);\n}\n\nfunction graphemeSubstring(str, start, end = Infinity) {\n  const g = graphemeSplit(str);\n  return g.slice(start, end).join(\"\");\n}\n<\/code><\/pre>\n<blockquote>\n<p><strong>Praxisregel:<\/strong> Sobald Nutzertext, Emojis oder Sprachen mit kombinierten Zeichen im Spiel sind, vermeide substring() f\u00fcr \u201esichtbare Zeichen\u201c. Nutze Codepoint- oder Graphem-basierte Alternativen.<\/p>\n<\/blockquote>\n<hr\/>\n<p><img alt=\"javascript substring\" decoding=\"async\" src=\"https:\/\/romejs.dev\/wp-content\/uploads\/2025\/10\/javascript_substring_ins6.jpg\" style=\"display:block; margin:20px auto; max-width:80%; height:auto;\"\/><\/p>\n<h2>H\u00e4ufige Fehler und wie du sie vermeidest<\/h2>\n<ul>\n<li><strong>Verwechselte Grenzen:<\/strong> Du willst Zeichen 0\u20134 und schreibst <code>substring(0, 5)<\/code>. Das ist korrekt. H\u00e4ufige Fehler entstehen, wenn das exklusive Ende vergessen wird. Tipp: kommentiere \u201eexklusive Endposition\u201c, wenn der Kontext es nicht klar macht.<\/li>\n<li><strong>Negative Indizes erwartet:<\/strong> substring() klemmt negativ auf 0. Wenn du \u201evom Ende\u201c z\u00e4hlen willst, nutze <em>slice()<\/em> oder berechne die Indizes relativ zur L\u00e4nge.<\/li>\n<li><strong>Start &gt; End nicht beachtet:<\/strong> substring() tauscht die Parameter \u2013 kann in Debug-Situationen verwirren. Wer leere Ergebnisse erwartet, nimmt <em>slice()<\/em>.<\/li>\n<li><strong>Unicode zerschnitten:<\/strong> vermeide substring() bei Emojis\/Graphemen, nutze Codepoint\/Graphem-Alternativen (siehe oben).<\/li>\n<li><strong>Fehlende Bound-Checks:<\/strong> verlasse dich nicht nur auf \u201eClamping\u201c. Pr\u00fcfe in kritischen Pfaden selbst die Werte, damit die Absicht im Code klar ist.<\/li>\n<li><strong>substr() weiterbenutzt:<\/strong> In neuem Code nicht mehr verwenden. Das API ist legacy; setze auf substring() oder slice().<\/li>\n<\/ul>\n<hr\/>\n<h2>Performanz und Speicher<\/h2>\n<p>F\u00fcr die meisten Anwendungsf\u00e4lle sind substring() und slice() in modernen Engines <em>nahezu gleichwertig<\/em>. Unterschiede h\u00e4ngen stark von Engine, Inputgr\u00f6\u00dfe und JIT-Optimierungen ab. Mikrobenchmarks variieren \u2013 plane deine API nach Semantik und Lesbarkeit, nicht nach vermeintlichen Pauschal-Speedvorteilen.<\/p>\n<ul>\n<li><strong>Komplexit\u00e4t:<\/strong> O(n) in der L\u00e4nge des extrahierten Teils.<\/li>\n<li><strong>Kurzlebige Substrings:<\/strong> Engines optimieren h\u00e4ufig f\u00fcr diese F\u00e4lle. H\u00e4ufige Substring-Operationen in Hot-Paths sind normalerweise unkritisch.<\/li>\n<li><strong>Gro\u00dfe Daten:<\/strong> Wenn du mehrfache Kopien sehr gro\u00dfer Strings erzeugst, achte auf Speicherverbrauch; streame oder arbeite segmentiert.<\/li>\n<\/ul>\n<pre><code class=\"language-js\">\/\/ Beispiel: segmentiertes Verarbeiten einer gro\u00dfen Datei (konzeptionell)\nfunction processInChunks(str, size = 64 * 1024) {\n  for (let i = 0; i &lt; str.length; i += size) {\n    const chunk = str.substring(i, Math.min(i + size, str.length));\n    \/\/ ... verarbeiten ...\n  }\n}\n<\/code><\/pre>\n<hr\/>\n<h2>Robuste Muster und Best Practices<\/h2>\n<h3>1) Grenzen explizit behandeln<\/h3>\n<pre><code class=\"language-js\">function safeSubstring(str, start, end) {\n  const len = str.length;\n  const s = Math.max(0, Math.min(len, start | 0)); \/\/ trunc to int + clamp\n  const e = end == null ? len : Math.max(0, Math.min(len, end | 0));\n  return s &lt;= e ? str.substring(s, e) : str.substring(e, s); \/\/ bewusstes Spiegeln\n}\n<\/code><\/pre>\n<h3>2) Negative Indizes bewusst via slice oder Umrechnung<\/h3>\n<pre><code class=\"language-js\">function fromEnd(str, startFromEnd, endFromEnd) {\n  const len = str.length;\n  const s = Math.max(0, len + startFromEnd);\n  const e = endFromEnd == null ? len : Math.max(0, len + endFromEnd);\n  return str.slice(s, e);\n}\n\nfromEnd(\"abcdef\", -3);       \/\/ \"def\"\nfromEnd(\"abcdef\", -4, -1);   \/\/ \"cde\"\n<\/code><\/pre>\n<h3>3) Lesbarkeit vor Mikro-Optimierung<\/h3>\n<p>Wenn das Team h\u00e4ufiger negative Indizes erwartet, etabliere <em>slice()<\/em> als Standard. Wenn \u201eStart\/End exklusive\u201c zentral ist, <em>substring()<\/em>. Lege dich teamweit fest und halte dich an einheitliche Muster.<\/p>\n<h3>4) String-APIs kombinieren<\/h3>\n<pre><code class=\"language-js\">\/\/ Bereich zwischen zwei Marken extrahieren\nfunction between(haystack, a, b) {\n  const i = haystack.indexOf(a);\n  if (i === -1) return \"\";\n  const j = haystack.indexOf(b, i + a.length);\n  if (j === -1) return \"\";\n  return haystack.substring(i + a.length, j);\n}\n\nbetween(\"foo [bar] baz\", \"[\", \"]\"); \/\/ \"bar\"\n<\/code><\/pre>\n<h3>5) TypeScript-Hinweis<\/h3>\n<p>Die Signatur ist eindeutig, dennoch lohnt sich ein kleines Helper-API f\u00fcr dom\u00e4nenspezifische Namen:<\/p>\n<pre><code class=\"language-ts\">function extractPrefix(str: string, endExclusive: number): string {\n  return str.substring(0, endExclusive);\n}\n<\/code><\/pre>\n<hr\/>\n<h2>Edge-Cases im Detail<\/h2>\n<ul>\n<li><strong>start = end<\/strong>: Immer leerer String.<\/li>\n<li><strong>start &gt; end<\/strong>: Auto-Swap \u2013 kann Bugs verdecken. Wenn du so einen Fall als Fehler behandeln willst, pr\u00fcfe die Reihenfolge vorher und wirf eine Exception.<\/li>\n<li><strong>Argumente als Strings:<\/strong> \u201e2\u201c wird zu 2; Achte auf unbewusste Typkonvertierungen aus Formularwerten.<\/li>\n<li><strong>this-Kontext:<\/strong> Direkter Aufruf an String-Instanz unkritisch. <code>String.prototype.substring.call(obj, ...)<\/code> coerct <code>obj<\/code> zu String. <code>null<\/code>\/<code>undefined<\/code> als this werfen.<\/li>\n<\/ul>\n<pre><code class=\"language-js\">String.prototype.substring.call(12345, 1, 3); \/\/ \"23\"\nString.prototype.substring.call(null, 1, 3); \/\/ TypeError\n<\/code><\/pre>\n<hr\/>\n<h2>Kompatibilit\u00e4t und Laufzeitumgebungen<\/h2>\n<p>substring() ist seit den Anf\u00e4ngen von JavaScript vorhanden und wird in allen modernen Browsern sowie in Node.js unterst\u00fctzt.<\/p>\n<table>\n<thead>\n<tr>\n<th>Umgebung<\/th>\n<th>Support<\/th>\n<th>Hinweise<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Chrome, Edge, Firefox, Safari<\/td>\n<td>Vollst\u00e4ndig<\/td>\n<td>Breit verf\u00fcgbar seit vielen Jahren<\/td>\n<\/tr>\n<tr>\n<td>Node.js<\/td>\n<td>Vollst\u00e4ndig<\/td>\n<td>L\u00e4uft auf V8; substring wie im Browser<\/td>\n<\/tr>\n<tr>\n<td>IE (historisch)<\/td>\n<td>Vollst\u00e4ndig<\/td>\n<td>Legacy-Umgebungen sollten vermieden werden<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<blockquote>\n<p><strong>Gut zu wissen:<\/strong> <em>substr()<\/em> ist in vielen Engines noch vorhanden, gilt aber als legacy. Setze in neuem Code auf substring() oder slice().<\/p>\n<\/blockquote>\n<hr\/>\n<h2>Cheatsheet: die wichtigsten Muster kompakt<\/h2>\n<ul>\n<li><strong>Erste n Zeichen:<\/strong> <code>str.substring(0, n)<\/code><\/li>\n<li><strong>Letzte n Zeichen:<\/strong> <code>str.substring(str.length - n)<\/code><\/li>\n<li><strong>Von a bis b (exklusiv):<\/strong> <code>str.substring(a, b)<\/code><\/li>\n<li><strong>Vom Ende aus (lieber slice):<\/strong> <code>str.slice(-n)<\/code><\/li>\n<li><strong>Zwischen zwei Marken:<\/strong> <code>str.substring(str.indexOf(a) + a.length, str.indexOf(b, ...))<\/code><\/li>\n<li><strong>Unicode-sicher (Codepoints):<\/strong> <code>Array.from(str).slice(a, b).join(\"\")<\/code><\/li>\n<\/ul>\n<hr\/>\n<h2>Beispiele aus realen Projekten<\/h2>\n<h3>1) Versionsstrings parsen<\/h3>\n<pre><code class=\"language-js\">function parseSemver(v) {\n  \/\/ \"1.2.3-alpha+build.5\"\n  const plus = v.indexOf(\"+\");\n  const baseAndPre = plus === -1 ? v : v.substring(0, plus);\n  const meta = plus === -1 ? \"\" : v.substring(plus + 1);\n\n  const dash = baseAndPre.indexOf(\"-\");\n  const base = dash === -1 ? baseAndPre : baseAndPre.substring(0, dash);\n  const pre = dash === -1 ? \"\" : baseAndPre.substring(dash + 1);\n\n  const [major, minor, patch] = base.split(\".\").map(Number);\n  return { major, minor, patch, pre, meta };\n}\n<\/code><\/pre>\n<h3>2) Logzeilen normalisieren<\/h3>\n<pre><code class=\"language-js\">function trimLogLine(line, max = 120) {\n  return line.length &gt; max ? line.substring(0, max - 1) + \"\u2026\" : line;\n}\n<\/code><\/pre>\n<h3>3) Token-Parsing (Header: \u201eBearer \u2026\u201c)<\/h3>\n<pre><code class=\"language-js\">function extractBearerAuth(header) {\n  const prefix = \"Bearer \";\n  return header.startsWith(prefix) ? header.substring(prefix.length) : \"\";\n}\n<\/code><\/pre>\n<h3>4) CSV-Feld (einfacher Fall, keine Quotes)<\/h3>\n<pre><code class=\"language-js\">function nthCsvField(line, n) {\n  let start = 0, end, pos = 0;\n  while (pos &lt; n) {\n    end = line.indexOf(\",\", start);\n    if (end === -1) return \"\";\n    start = end + 1;\n    pos++;\n  }\n  end = line.indexOf(\",\", start);\n  return end === -1 ? line.substring(start) : line.substring(start, end);\n}\n<\/code><\/pre>\n<hr\/>\n<h2>Debugging-Tipps<\/h2>\n<ul>\n<li><strong>Klarheit \u00fcber End-Exklusivit\u00e4t:<\/strong> Logge bewusst Start\/End in Debug-Ausgaben und benenne Variablen <code>endExclusive<\/code>, um Missverst\u00e4ndnisse zu vermeiden.<\/li>\n<li><strong>Unicode-Checks:<\/strong> Wenn seltsame Zeichen entstehen, gib <code>[...str]<\/code> oder <code>Array.from(str)<\/code> aus, um Codepoints zu inspizieren.<\/li>\n<li><strong>Assert-Reihenfolge:<\/strong> F\u00fcge Dev-Asserts ein, wenn <code>start &gt; end<\/code> in deinem Use-Case niemals vorkommen darf.<\/li>\n<\/ul>\n<hr\/>\n<h2>Wann substring(), wann slice()?<\/h2>\n<p>Beide sind valide. Entscheide nach Semantik deines Codes:<\/p>\n<ul>\n<li><strong>substring():<\/strong> Klar ersichtlich, wenn du mit Indizes als Bereich (Start inklusive, Ende exklusiv) arbeitest und negatives Indexing ausgeschlossen ist.<\/li>\n<li><strong>slice():<\/strong> Sinnvoll, wenn du h\u00e4ufig \u201evom Ende\u201c z\u00e4hlst oder leeres Ergebnis bei vertauschten Werten erwartest.<\/li>\n<\/ul>\n<p>Wenn du im Team eine gemeinsame Konvention definierst, vermeidest du kognitive Reibung und Bug-Klassen durch unterschiedliche Erwartungen.<\/p>\n<hr\/>\n<h2>Qualit\u00e4tssicherung<\/h2>\n<ul>\n<li><strong>Tests:<\/strong> Spezifische Tests f\u00fcr Grenzwerte (0, L\u00e4nge, -1, length+1, start=end, start&gt;end).<\/li>\n<li><strong>Unicode-F\u00e4lle:<\/strong> Lege Tests mit Emojis, zusammengesetzten Zeichen, RTL-Skripten an.<\/li>\n<li><strong>Statische Analyse:<\/strong> Lintern beibringen, <em>substr()<\/em> zu verbieten, und ggf. Konsistenz-Regeln f\u00fcr <em>slice()<\/em>\/<em>substring()<\/em> zu erzwingen.<\/li>\n<\/ul>\n<hr\/>\n<h2>Fazit<\/h2>\n<p><strong>substring()<\/strong> ist ein stabiles, breit unterst\u00fctztes Werkzeug f\u00fcr String-Zuschnitte in JavaScript. Es \u00fcberzeugt durch einfache Semantik (Start inklusive, Ende exklusiv), tolerantes Verhalten (Clamping, Auto-Swap) und gute Lesbarkeit in klassischen Extraktionsaufgaben. In Situationen, in denen du mit negativen Indizes arbeitest oder bewusst ein leeres Ergebnis bei vertauschten Parametern m\u00f6chtest, ist <strong>slice()<\/strong> die bessere Wahl. <strong>substr()<\/strong> solltest du f\u00fcr neuen Code meiden. Achte in jedem Fall auf Unicode-Fallen und nutze bei Bedarf Codepoint- oder Graphem-basierte Alternativen. Wenn du klare Teamkonventionen definierst, Grenzwerte testest und bewusst mit den Parametern umgehst, ist substring() ein verl\u00e4sslicher Baustein f\u00fcr robuste Textverarbeitung \u2013 von einfachen Maskierungen bis hin zu pr\u00e4ziser Segmentierung komplexer Strings. Ein abschlie\u00dfender Hinweis: In diesem Tutorial hast du gelernt, wie substring() funktioniert \u2013 die Prinzipien von ECMAScript, <a href=\"https:\/\/romejs.dev\/javascript-foreach\/\">Array-Iteration<\/a> und JavaScript erm\u00f6glichen es, Code klar und effizient zu gestalten.<\/p>\n<hr\/>\n<h2>FAQ<\/h2>\n<h3>Ist javascript substring schneller als slice?<\/h3>\n<p>In modernen Engines sind die Unterschiede meist gering und kontextspezifisch. Nutze die Methode, die semantisch besser passt. Miss Performance nur, wenn sie wirklich kritisch ist, und zwar in deiner Zielumgebung.<\/p>\n<h3>Warum gibt substring(start, end) das Zeichen bei end nicht zur\u00fcck?<\/h3>\n<p>Das Design folgt dem \u00fcblichen Muster \u201eStart inklusive, Ende exklusiv\u201c. Dadurch lassen sich benachbarte Bereiche ohne Off-by-one-Fehler aneinanderreihen.<\/p>\n<h3>Wie bekomme ich die letzten n Zeichen mit substring()?<\/h3>\n<p>Berechne den Start relativ zur L\u00e4nge: <code>str.substring(str.length - n)<\/code>. Alternativ ist <code>str.slice(-n)<\/code> noch kompakter.<\/p>\n<h3>Warum ist substr() nicht empfohlen?<\/h3>\n<p>substr() gilt als legacy und ist in Standards nicht mehr priorisiert. Es funktioniert zwar in vielen Umgebungen, kann aber perspektivisch entfallen. Nutze substring() oder slice().<\/p>\n<h3>Wie gehe ich mit Emojis sicher um?<\/h3>\n<p>Nutze <code>Array.from(str)<\/code> (Codepoint-basiert) oder <code>Intl.Segmenter<\/code> (Graphem-basiert), um sichtbare Zeichen nicht zu zerschneiden. substring() arbeitet auf UTF-16 Code Units und kann Emojis besch\u00e4digen.<\/p>\n<h3>Was passiert bei negativen oder NaN-Indizes?<\/h3>\n<p>substring() klemmt negative Werte auf 0; <code>NaN<\/code> wird wie 0 behandelt. Werte \u00fcber der L\u00e4nge werden auf die L\u00e4nge geklemmt. Bei <code>start &gt; end<\/code> tauscht substring() die Parameter.<\/p>\n<h3>Wie extrahiere ich Text zwischen zwei Markern?<\/h3>\n<p>Nutze <code>indexOf<\/code> f\u00fcr die Marken und dann <code>substring(start, end)<\/code>. Achte auf -1-F\u00e4lle, wenn ein Marker fehlt.<\/p>\n<h3>Kann ich substring() auf Nicht-Strings anwenden?<\/h3>\n<p>Indirekt ja: <code>String.prototype.substring.call(value, ...)<\/code> coerct <code>value<\/code> zu String. F\u00fcr <code>null<\/code>\/<code>undefined<\/code> wird ein TypeError geworfen.<\/p>\n<h3>Wie vermeide ich Off-by-one-Fehler?<\/h3>\n<p>Kommentiere bei Bedarf \u201eEnde exklusiv\u201c, verwende sprechende Variablennamen (z. B. <code>endExclusive<\/code>) und schreibe gezielte Tests f\u00fcr Grenzf\u00e4lle.<\/p>\n<h3>Gibt es eine einfache Faustregel f\u00fcr substring vs slice?<\/h3>\n<p>Ja: Wenn du keine negativen Indizes brauchst und Start\/End exklusiv-expressiv ausdr\u00fccken willst, substring(). Wenn du oft \u201evom Ende\u201c aus z\u00e4hlst oder explizit leere Ergebnisse bei vertauschten Parametern bevorzugst, slice().<\/p>\n","protected":false},"excerpt":{"rendered":"<p>substring() ist eine der meistgenutzten String-Methoden in JavaScript. Sie extrahiert Teile eines Textes, ohne das Original zu ver\u00e4ndern. In diesem Leitfaden zeige ich dir pr\u00e4zise, wie substring() funktioniert, worin es sich von slice() und substr() unterscheidet, welche Edge-Cases dich in der Praxis erwarten, wie du Unicode- und Emoji-Fallen meidest, und welche Best Practices sich bew\u00e4hrt [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":33,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-36","post","type-post","status-publish","format-standard","has-post-thumbnail","category-javascript","entry"],"_links":{"self":[{"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/posts\/36","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/comments?post=36"}],"version-history":[{"count":1,"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/posts\/36\/revisions"}],"predecessor-version":[{"id":120,"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/posts\/36\/revisions\/120"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/media\/33"}],"wp:attachment":[{"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/media?parent=36"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/categories?post=36"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/romejs.dev\/wp-json\/wp\/v2\/tags?post=36"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}