Stränglängdsberäknare

Klistra in en sträng så rapporterar verktyget dess längd i fyra olika bemärkelser, JavaScript-stil .length (UTF-16-kodenheter), Unicode-kodpunkter, grafemkluster (det användare uppfattar som ett tecken) och UTF-8-byte (det din databaskolumn faktiskt lagrar). Dessa tal stämmer inte överens för någon sträng med emoji, flaggor eller kombinationsmärken, och den oenigheten är källan till många buggar.

De fyra bemärkelserna av stränglängd

  1. 1

    UTF-16-kodenheter

    Vad `str.length` returnerar i JavaScript. 1 för de flesta tecken, 2 för varje kodpunkt bortom U+FFFF (emoji, antika skriftsystem).

  2. 2

    Kodpunkter

    En per Unicode-skalär. Emoji är 1 var; ZWJ-sekvenser är flera.

  3. 3

    Grafemkluster

    Vad en användare kallar "ett tecken". `🇺🇸` är 2 kodpunkter men 1 grafem. `n̈` är 2 kodpunkter men 1 grafem.

  4. 4

    UTF-8-byte

    Vad din DB lagrar. ASCII = 1 byte var; vanlig europeisk = 2; CJK = 3; de flesta emoji = 4.

Exempel

Sträng JS .length Kodpunkter Grafem UTF-8-byte
hello 5 5 5 5
café 4 4 4 5
😀 2 1 1 4
🇺🇸 4 2 1 8
👨‍👩‍👧 (familj) 8 5 1 18
n̈ (n + trema) 2 2 1 3

Varför talen skiljer sig

JavaScript-strängar är UTF-16, så en kodpunkt över U+FFFF lagras som ett surrogatpar, två UTF-16-kodenheter. "😀".length === 2. Användare hatar detta eftersom de tänker på 😀 som ett tecken.

Grafem går längre: en landsflagga är två regionala-indikator-kodpunkter som användaren ser som en flagga. "🇺🇸".length === 4 i JavaScript, vilket känns absurt, men så är det. För att iterera över grafem, använd Intl.Segmenter (modernt), biblioteket grapheme-splitter eller hantera manuellt.

UTF-8-byte: vad din databas lagrar

För en kolumn typad VARCHAR(255):

  • I MySQL utf8 (faktiskt: utf8mb3) är 255 byte. café tar 5 byte, så du får plats med 51 kopior.
  • I MySQL utf8mb4 (riktig UTF-8, inklusive emoji) är det fortfarande byte men kodningen stöder 4-byte-sekvenser.
  • I Postgres VARCHAR(255) är 255 tecken (kodpunkter), inte byte.
  • I SQL Server VARCHAR varierar det med sortering; NVARCHAR räknar 2-byte UCS-2-enheter.

Om du dimensionerar databasfält efter användarsynlig teckengräns, använd byte × 4 för säkerhets skull i UTF-8-kolumner, varje grafem kan potentiellt ta upp till 4 byte per kodpunkt, med ZWJ-sekvenser som lägger till mer.

Twitter-stil teckenräkning

Twitter räknar en tweet med en egen regel: kodpunkter, men emoji och CJK-ideogram räknas som 2. En tweet med 100 % ASCII kan vara 280 tecken; en tweet med 140 emoji når taket vid 140 “tecken”.

SMS-räkning: 160 tecken i GSM 7-bitar. Varje icke-GSM-tecken (á, é, ñ, emoji) växlar kodningen till UCS-2, och din meddelandelängd faller till 70 tecken.

Praktiska användningar

  • Dimensionering av databaskolumner, kontrollera byteantalet innan du skriver en migrering.
  • API-kvotkontroll, de flesta API:er räknar byte, inte tecken.
  • Formulärvalidering, visa användaren ett korrekt teckenantal som matchar deras förväntan (grafem).
  • Prestandafelsökning, varför itererar den här regexen långsamt? Eftersom indata är 3x längre i kodenheter än i grafem.

Vanliga frågor

Den emojin är en ZWJ-sekvens som kombinerar flera kodpunkter (t.ex. en familjeemoji är 7 kodpunkter). Twitter räknar den som 2 tecken enligt Unicode-viktregeln; din redigerare visar 1 grafem. Båda har tekniskt sett rätt, de mäter bara olika saker.

I UTF-8-databaser, tillåt 4 byte per förväntat tecken för säkerhets skull. Ett fält på 100 tecken (grafem) bör vara VARCHAR(400) byte, eller om din DB räknar i tecken som Postgres, VARCHAR(100) med teckenuppsättningshantering.

I JavaScript: det beror på kompositionsformen. NFC-sammansatt (U+00E1) har längd 1; NFD-dekomponerad (U+0061 + U+0301) har längd 2. Samma synliga tecken, olika bytesekvenser.

Familje- och yrkesemoji är långa ZWJ-sekvenser. Teckensnitt utan fullt stöd renderar varje kodpunkt som en separat glyf, så 👨‍💻 blir 👨+💻. Att uppgradera OS-teckensnittet löser det.

Relaterade verktyg

Verktyget finns på andra språk