stringkey

package
v1.148.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package stringkey solves the practical problem of deriving a stable, compact, non-cryptographic key from multiple text fields for fast lookup, deduplication, and idempotency-style identifiers.

Problem

Applications frequently need a deterministic key built from several strings (for example: first name + last name + country, or provider + external ID + scope). Building these keys manually is error-prone because equivalent inputs may differ only by case, whitespace, or Unicode composition. stringkey applies a canonical normalization pipeline before hashing so semantically equivalent inputs map to the same key more often.

How It Works

New builds a StringKey from one or more input fields using this pipeline:

  1. Trim leading and trailing Unicode whitespace for each field.
  2. Collapse repeated Unicode whitespace to a single space.
  3. Convert text to lowercase.
  4. Concatenate fields using a tab separator (`\t`) to preserve boundaries.
  5. Apply Unicode NFC normalization (equivalent to NFD then NFC).
  6. Hash the resulting byte sequence with FarmHash64.

The resulting key is stored as an internal uint64 and can be retrieved in multiple representations:

Two normalization details are worth calling out:

  • Normalization is NFC, not NFKC. Canonically equivalent forms (such as precomposed vs decomposed accents) collapse together, but compatibility variants do not: ligatures (for example "ff"), full-width vs half-width forms, and super/subscripts are left distinct.
  • Lowercasing uses the locale-independent unicode.ToLower simple mapping, not language-tailored case folding. For example, the Turkish dotless "ı" and dotted "İ" are not special-cased.

Key Features

  • Deterministic canonicalization across case/spacing/Unicode variants.
  • Compact 64-bit key suitable for indexing and caching.
  • Multiple output formats for storage, logs, and URLs.
  • Fast, allocation-light hashing path for small field sets.

Stability

For a fixed input, the key is fully deterministic and does not change across runs, architectures, or Go versions: FarmHash64 is a fixed algorithm and the representations are plain integer encodings.

The one dependency to be aware of is the Unicode normalization step, which uses the Unicode data tables shipped by golang.org/x/text. Keys for pure-ASCII input and for long-assigned characters are effectively permanent. Only rare or newly-assigned code points can normalize differently if the golang.org/x/text Unicode version advances, which would change their keys across such an upgrade. If you persist keys and must survive Unicode-table upgrades unchanged, pin the golang.org/x/text version alongside the stored keys.

Important Limits

This package is not cryptographically secure and must not be used for security tokens, signatures, or untrusted collision-resistant identifiers.

It is designed for reasonably small input sizes and a moderate number of keys. According to the birthday bound for a 64-bit hash space (~1.8x10^19):

  • collision probability is about 1% around 6.1x10^8 generated keys;
  • collision probability is about 50% around 5.1x10^9 generated keys.

Choose a larger hash or cryptographic construction when your scale or threat model requires stronger collision guarantees.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type StringKey

type StringKey struct {
	// contains filtered or unexported fields
}

StringKey stores the encoded key.

func New

func New(fields ...string) *StringKey

New constructs deterministic FarmHash64 key from normalized input strings (whitespace/case/Unicode normalized).

Example
package main

import (
	"fmt"

	"github.com/tecnickcom/nurago/pkg/stringkey"
)

func main() {
	// input strings
	args := []string{
		"0123456789",
		"abcdefghijklmnopqrstuvwxyz",
		"Lorem ipsum dolor sit amet",
	}

	// generate a new key
	sk := stringkey.New(args...)

	fmt.Println(sk)

}
Output:
2p8dmari397l8

func (*StringKey) Hex

func (sk *StringKey) Hex() string

Hex returns fixed 16-character lowercase hexadecimal representation of key, zero-padded.

Example
package main

import (
	"fmt"

	"github.com/tecnickcom/nurago/pkg/stringkey"
)

func main() {
	// generate a new key as fixed-length 16 digits hexadecimal string key.
	k := stringkey.New(
		"0123456789",
		"abcdefghijklmnopqrstuvwxyz",
		"Lorem ipsum dolor sit amet",
	).Hex()

	fmt.Println(k)

}
Output:
b19b688e8e3229ac

func (*StringKey) Key

func (sk *StringKey) Key() uint64

Key returns raw uint64 key value.

Example
package main

import (
	"fmt"

	"github.com/tecnickcom/nurago/pkg/stringkey"
)

func main() {
	// generate a new key as uint64
	k := stringkey.New(
		"0123456789",
		"abcdefghijklmnopqrstuvwxyz",
		"Lorem ipsum dolor sit amet",
	).Key()

	fmt.Println(k)

}
Output:
12797937727583693228

func (*StringKey) String

func (sk *StringKey) String() string

String returns variable-length base-36 string representation of key.

Example
package main

import (
	"fmt"

	"github.com/tecnickcom/nurago/pkg/stringkey"
)

func main() {
	// generate a new key as 36-char encoded string
	k := stringkey.New(
		"0123456789",
		"abcdefghijklmnopqrstuvwxyz",
		"Lorem ipsum dolor sit amet",
	).String()

	fmt.Println(k)

}
Output:
2p8dmari397l8

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL