nkb boundary

Podajesz limit, który deklaruje pole, i dostajesz wartości, które go testują: pustą, o jeden krótszą, dokładnie równą i o jeden dłuższą, ze znaków, które ważą inaczej w bajtach i w jednostkach UTF-16.

nkb boundary [--max-length N] [--min-length N]
             [--unit graphemes|code-points|utf16|bytes]
             [--format json|csv|lines] [--escaped|--raw] [--base64]

Co tworzy?

Dla pola, które przyjmuje najwyżej 50 znaków: wartość pustą, a potem wartości o długości 49, 50 i 51 w każdym z sześciu wypełnień. Z --min-length dochodzą długości wokół najmniejszej, jaką pole przyjmuje, a długość wspólna dla dwóch granic pojawia się raz. Każda wartość mówi, jak długa jest w czterech jednostkach i czy jej długość mieści się w limicie.

Paczki to listy nietypowych znaków. To polecenie odpowiada na jedno zdanie, które specyfikacja mówi o polu.

Dlaczego sześć wypełnień?

Bo „50 znaków” to jedna z czterech liczb, a rzadko wiadomo, którą z nich liczy aplikacja:

Pięćdziesiąt liter a to pięćdziesiąt w każdej jednostce, więc nie odróżni jednej od drugiej. Pięćdziesiąt liter dwubajtowych to pięćdziesiąt znaków i sto bajtów, pięćdziesiąt emoji to sto jednostek UTF-16, a pięćdziesiąt emoji rodziny to dla oka pięćdziesiąt znaków i dwieście pięćdziesiąt punktów kodowych. Pole, które przyjmuje pięćdziesiąt liter a, a odrzuca albo ucina którąś z pozostałych wartości, właśnie powiedziało, co liczy.

Żaden z tych znaków nie zmienia się w żadnej postaci normalnej Unicode, więc pole, które normalizuje tekst, nadal dostaje długość, o którą chodziło.

Przykłady

Jedna wartość na wiersz, do wklejania albo dla testu:

$ nkb boundary --max-length 50 --format lines > limit-50.txt
nkb boundary: 19 values, 1500 code points, 4350 bytes

CSV, z czterema rozmiarami każdej wartości obok siebie:

$ nkb boundary --max-length 50 --format csv
nkb boundary: 19 values, 1500 code points, 4350 bytes
id,name,value,fill,length,within,graphemes,code_points,utf16_units,bytes
empty,Empty value,,,0,true,0,0,0,0
letters-49,49 x a,aaaaa...,letters,49,true,49,49,49,49
letters-50,50 x a,aaaaa...,letters,50,true,50,50,50,50
letters-51,51 x a,aaaaa...,letters,51,false,51,51,51,51
...
two-byte-50,50 x U+0142,...,two-byte,50,true,50,50,50,100
four-byte-50,50 x U+1F600,...,four-byte,50,true,50,50,100,200
cluster-50,50 x U+1F468 U+200D U+1F469 U+200D U+1F467,...,cluster,50,true,50,250,400,900

Limit liczony w bajtach. Każda wartość ma dokładnie tyle bajtów, ile mówi jej wiersz, z literą a z przodu tam, gdzie całe znaki nie dają tej liczby:

$ nkb boundary --max-length 50 --unit bytes --format csv
...
two-byte-49,1 x a + 24 x U+0142,...,two-byte,49,true,25,25,25,49
two-byte-50,25 x U+0142,...,two-byte,50,true,25,25,25,50
two-byte-51,1 x a + 25 x U+0142,...,two-byte,51,false,26,26,26,51

O którą jednostkę poprosić?

Zacznij bez --unit. Wartości są wtedy liczone tak, jak liczy człowiek, a odpowiedź aplikacji na cięższe wypełnienia pokazuje, co liczy ona.

Potem uruchom polecenie jeszcze raz, w tej jednostce. Wartość o 51 bajtach z litery dwubajtowej to jedno a i dwadzieścia pięć liter, więc pole, które tnie na 50 bajtach, przecina ostatnią literę w połowie. W utf16 to samo spotyka emoji, a zostaje pół znaku: tekst, który przestaje się wyświetlać, zapis, który się nie udaje, albo błąd daleko od pola. Wartość z całych znaków aż do limitu nigdy tego nie wywoła i dlatego dopełnienie stoi z przodu.

Jak czytać counterstring?

Przed każdą gwiazdką stoi numer jej własnego miejsca. To counterstring o długości 51:

*3*5*7*9*12*15*18*21*24*27*30*33*36*39*42*45*48*51*

Jeśli w polu zostało ...42*45*48*51, ostatnia gwiazdka stoi na miejscu 48 i są po niej dwa znaki, więc weszło 50. Miejsce cięcia czytasz z samego pola, bez liczenia i bez drugiego narzędzia.

Counterstring to cyfry i gwiazdki. Pole, które przyjmuje same litery, odrzuci go z tego powodu i od tego jest wypełnienie letters. Pole, które renderuje Markdown, może połknąć gwiazdki.

Co obiecuje „within”?

Że długość wartości mieści się w podanym limicie, w podanej jednostce, i nic więcej. Pole wymagane nadal odrzuci wartość pustą, a pole przyjmujące same litery nadal odrzuci emoji. Gdy wartość mieszcząca się w limicie zostaje odrzucona z powodu długości, to albo aplikacja liczy w innej jednostce, albo limit jest inny, niż mówi specyfikacja. Jedno i drugie warto zgłosić.

Opcje

--max-length N

Najwięcej, ile pole przyjmuje, od 1 do 100000

--min-length N

Najmniej, ile pole przyjmuje, od 1 do 100000

--unit graphemes|code-points|utf16|bytes

W czym liczony jest limit (domyślnie: graphemes)

--format json|csv|lines

Jedno z: json, csv, lines. Co zapisuje każdy z nich, mówią formaty niżej.

--escaped

Wypisuje wartości tak, jak zapisuje je plik paczki

--raw

Wypisuje wartości dosłownie

--base64

Koduje wartości dla kanałów, które psują tekst

-h, --help

Pokazuje tę pomoc i kończy kodem 0

Wypełnienia

letters

Litera a

counterstring

Liczby i gwiazdki, jak w *3*5*7*9*12*. Każda liczba to miejsce gwiazdki, która po niej stoi, więc pole, które ucięło wartość, samo pokazuje, gdzie ucięło

two-byte

Litera o dwóch bajtach (U+0142)

three-byte

Znak o trzech bajtach (U+20AC)

four-byte

Emoji o czterech bajtach i dwóch jednostkach UTF-16 (U+1F600)

cluster

Emoji rodziny: dla oka jeden znak, a pięć punktów kodowych

Jednostki

graphemes

Znaki tak, jak liczy je człowiek. Jednostka domyślna

code-points

Punkty kodowe Unicode

utf16

Jednostki UTF-16, które liczy maxlength w przeglądarce i JavaScript

bytes

Bajty UTF-8

Formaty

json

Obie postacie każdej wartości, z jej wypełnieniem, długością, tym, czy mieści się w limicie, i rozmiarem we wszystkich czterech jednostkach. Format domyślny

csv

Jeden wiersz na wartość, z tymi samymi kolumnami. Domyślnie w postaci escapowanej

lines

Jedna wartość na wiersz. Wartość pusta to pusty wiersz

Kody wyjścia

Pomoc tego polecenia nie wymienia własnych kodów wyjścia. Liczby znaczą to samo w każdym poleceniu: Kody wyjścia

Pomoc, tak jak wypisuje ją program

Co wypisuje nkb boundary --help (nkb 0.3.0).

nkb boundary - make the values that test the length limit of a field

Usage:
  nkb boundary [--max-length N] [--min-length N]
               [--unit graphemes|code-points|utf16|bytes]
               [--format json|csv|lines] [--escaped|--raw] [--base64]

Give the limit the field states and get the values worth trying: nothing,
then one under, exactly at and one over each bound. Every length comes in
six fills, because "50 characters" is a different number in each unit.

Fills:
  letters        The letter a
  counterstring  Numbers and stars, as in *3*5*7*9*12*. Each number is the
                 place of the star after it, so a field that cut the value
                 shows where it cut
  two-byte       A letter of two bytes (U+0142)
  three-byte     A sign of three bytes (U+20AC)
  four-byte      An emoji of four bytes and two UTF-16 units (U+1F600)
  cluster        A family emoji: one character to the eye, five code points

Units:
  graphemes    Characters as a person counts them. The default
  code-points  Unicode code points
  utf16        UTF-16 units, which a browser's maxlength and JavaScript count
  bytes        Bytes of UTF-8

Counted in graphemes, 50 two-byte letters are 100 bytes and 50 emoji are
100 UTF-16 units, so a field that refuses or cuts them counts something
else. Run again in that unit: a value then has exactly that many units,
padded with the letter a in front, and the limit falls inside the last
character of the value one over it.

Values go to standard output and the account of what came out goes to
standard error. "within" says whether the length of a value is inside the
limit and nothing more: a required field still refuses the empty value.

Formats:
  json     Both forms of every value, with its fill, its length, whether it
           is within the limit and its size in all four units. The default
  csv      One row per value, with the same columns. Escaped by default
  lines    One value per line. The empty value is an empty line

Options:
      --max-length N  The most the field takes, from 1 to 100000
      --min-length N  The least the field takes, from 1 to 100000
      --unit          What the limit is counted in (default: graphemes)
      --escaped       Print values as a pack file stores them
      --raw           Print values literally
      --base64        Encode values, for channels that damage text
  -h, --help          Show this help and exit with 0