goslugify

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 7, 2020 License: Apache-2.0 Imports: 5 Imported by: 1

README

goslugify

A slug is a "short label for something". In the django glossary it is defined as:

A short label for something, containing only letters, numbers, underscores or hyphens. They’re generally used in URLs. For example, in a typical blog entry URL: https://www.djangoproject.com/weblog/2008/apr/12/spring/ the last bit (spring) is the slug.

There are some libraries out there for Golang, for example gosimple/slug. These libraries were not as flexible as I would like, and so I created this (hopefully easy to use but flexible) library.

Documentation

You can find the documentation on godoc.org including some examples.

Simple Usage

The documentation contains some simple example, but probably the easiest way to do something is to use the GenerateSlug function:

import (
    "fmt"
    "github.com/FabianWe/goslugify"
)

func main() {
    fmt.Println(goslugify.GenerateSlug("Gophers! The most interesting species of rodents"))
}

This will generate gophers-the-most-interesting-species-of-rodents. That's it.

What Will it Do By Default?

By default, the following conversion rules are applied to convert a string to a slug:

  1. Remove invalid UTF-8 codepoints
  2. Convert to UTF-8 normal form NKFC, see this blog post and this go package
  3. Convert to lower case
  4. Replace whitespaces by "-"
  5. Replace all dash symbols and hyphens by "-" (there is not just "-" in UTF-8)
  6. Translate umlauts, for example "ä" to "ae", "ß" to "ss""
  7. Drop everything that is not in a-zA-Z0-9-_
  8. Remove occurrences of two or more "-" by a single "-"
  9. Remove all leading and trailing "-"

Important note: Don't assume that this is exactly what happens all the time over different versions. Even in a new release of the same major release this behavior is likely to change if new functionality gets added. So don't assume that GenerateSlug always returns the same string! Once for example emoji support is added the result might look different. If you want to generate a slug to identify an object (in a database for example) always store this slug with the object, don't assume that a call to GenerateSlug(name) will return the exact same slug again (for the given object name).

If you don't write anything very specific for your own projects it's probably a good idea to share your function. I would be more than happy to include useful (and general) extensions in this project.

I Want to Customize the Generated Slugs

There are different ways to customize the behavior, one that is rather simple and should be sufficient in 90% of all use cases.

The Easy Way

Create an instance of SlugConfig and call Configure. This allows you to set the maximal length of the generated slugs, a different word separator, control lower case behavior and provide additional replacement maps. There are some examples in the documentation here, is another one:

import (
    "fmt"
    "github.com/FabianWe/goslugify"
)

func main() {
    config := goslugify.NewSlugConfig()
    config.TruncateLength = 30
    config.WordSeparator = '_'
    config.ToLower = false
    config.AddReplaceMap(goslugify.GetLanguageMap("en"))
    generator := config.Configure()
    fmt.Println(generator.GenerateSlug("Gophers & Other Rodents: A survey"))
}

This will produce "Gophers_and_Other_Rodents_A".

You can add more substitutions that should happen on the input string by calling AddReplaceMap. The language "de" for German is available too.

Again: The default behavior might change even through different versions of the same major release.

Extending With Custom Functions

Another way that is not too hard is to add your own functions that do some kind of string modification. Either implement StringModifierFunc or StringModifier, please read the documentation first.

Also make sure you understand the different phases of the generation as documented in SlugGenerator. Then you can use an existing SlugConfig and call GetPhases: This will give you the modifiers used for all three phases. You can simply append (to the back), create a copy and insert at the beginning, whatever you like. Then simply create a SlugGenerator instance with it.

Create a SlugGenerator by Hand

Probably the hardest way, you don't have the defaults that come with this library. Make sure that you get the order of the functions right, because it is important that they're executed in the correct order (in most cases). You probably want to look in the code anyway, so you might have a look at GetDefaultPreProcessors, GetDefaultProcessors and GetDefaultFinalizers. Again: Don't rely on the return value, it is probable that new modifiers will be added! So for example don't assume that the length will always be the same, or the element on a specific index is a certain modifier.

Is a String a Slug?

See the global function IsSlug for slugs generated with the global GenerateSlug function, and SlugConfig.GetValidator for validating a specific SlugConfig. There are some remarks in SlugConfig.GetValidator which you should read anyway. In short: Don't take the result too seriously.

Contribute

As mentioned before new functionality might be added in the same major release and thus the generated slugs in default mode might change. So if you for example plan to add emoji support or add a new language you can share it and I will happily add it to the project. Just contact me, via E-Mail or create a Pull Request.

TODOs
  • Add support for more languages
  • Add support for emojis

Version History

  • v1.0.0 on May 7th, 2020 (current)

License

Apache License, Version 2.0. See LICENSE file.

Documentation

Overview

Package goslugify implements a customizable slug generator written in Go.

You can either use the global function GenerateSlug or create a customized SlugGenerator. See the project homepage at https://github.com/FabianWe/goslugify for more details.

Index

Examples

Constants

View Source
const (
	LanguageEnglish = "en"
	LanguageGerman  = "de"
)

Variables

View Source
var EnglishReplaceDict = map[string]string{
	"@": "at",
	"&": "and",
}

EnglishReplaceDict contains replacers for "@" ("at") and "&" ("and").

View Source
var GermanReplaceDict = map[string]string{
	"@": "at",
	"&": "und",
}

GermanReplaceDict contains replacers for "@" ("at") and "&" ("und").

Functions

func AddLanguageMap

func AddLanguageMap(language string, m StringReplaceMap)

AddLanguageMap adds a new language to the global language map store. This store can be used for language specific replacements.

func GenerateSlug

func GenerateSlug(in string) string

GenerateSlug generates a new slug containing only valid slug codepoints.

This returns a slug that should be good enough for most cases, if you want to configure the returned slug, for example set a max length, you can customize a SlugGenerator. See documentation there.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	fmt.Println(goslugify.GenerateSlug("Hello World!! Isn't this amazing?"))
}
Output:

hello-world-isnt-this-amazing

func IgnoreInvalidUTF8

func IgnoreInvalidUTF8(in string) string

IgnoreInvalidUTF8 is a StringModifierFunc that removes all invalid UTF-8 codepoints from the string. It is usually the first modifier called.

func IsSlug

func IsSlug(s string) bool

IsSlug tests if s is a valid slug.

Note: The result of this function can be used for testing etc. But it should not be used like a hard-coded assertion in a live system. For details see SlugConfig.GetValidator.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	isSlug1 := goslugify.IsSlug("foo-bar")
	isSlug2 := goslugify.IsSlug("foo")
	isSlug3 := goslugify.IsSlug("Foo-bar")
	isSlug4 := goslugify.IsSlug("-foo-bar")
	fmt.Println(isSlug1, isSlug2, isSlug3, isSlug4)
}
Output:

true true false false

func KeepAllFunc

func KeepAllFunc(r rune) (bool, string)

KeepAllFunc can be used to avoid to drop certain runes when a rune handle function is converted to a string modifier with RuneHandleFuncToStringModifierFunc. If this is the last function chained in a sequence of such functions all runes will be kept.

func ReplaceDashAndHyphens

func ReplaceDashAndHyphens(r rune) (bool, string)

ReplaceDashAndHyphens replaces any symbol that is considered a hyphen or a dash (according to unicode.Hyphen, unicode.Dash) and replaces it with the rune '-'.

func TranslateUmlaut

func TranslateUmlaut(r rune) (bool, string)

TranslateUmlaut translates the umlaut symbols (ö, ä, ü) as well as ß to a string without the umlaut, for example 'ö' --> "oe", 'ß' --> "ss".

func ValidSlugRuneReplaceFunc

func ValidSlugRuneReplaceFunc(r rune) (bool, string)

ValidSlugRuneReplaceFunc accepts all runes that are by default allowed in slugs: A-Z, a-z, 0-9, - and _.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	modifier := goslugify.RuneHandleFuncToStringModifierFunc(goslugify.ValidSlugRuneReplaceFunc)
	fmt.Println(modifier("abc!09?ۤABZ-_"))
}
Output:

abc09ABZ-_

Types

type ConstantReplacer

type ConstantReplacer struct {
	OldNew []string
	// contains filtered or unexported fields
}

ConstantReplacer is an implementation of StringModifier that replaces all occurrences of a word by another word. For this the list OldNew is used, it describes pairs (key, value) and must therefor always contain an even number of strings. See strings.Replacer for more details.

Note that you can append new key/value pairs to an existing replacer, but only before Modify is called for the first time.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	replacer := goslugify.NewConstantReplacer("foo", "bar")
	fmt.Println(replacer.Modify("hello foo bar"))
}
Output:

hello bar bar

func NewConstantReplacer

func NewConstantReplacer(oldnew ...string) *ConstantReplacer

NewConstantReplacer returns a new replacer given the key/value list.

func NewConstantReplacerFromMap

func NewConstantReplacerFromMap(m StringReplaceMap) *ConstantReplacer

NewConstantReplacerFromMap given the replacement strings as a map.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	replacer := goslugify.NewConstantReplacerFromMap(map[string]string{
		"42": "21",
	})
	fmt.Println(replacer.Modify("42 is only half the truth"))
}
Output:

21 is only half the truth

func (*ConstantReplacer) Modify

func (replacer *ConstantReplacer) Modify(in string) string

Modify replaces all occurrences in the string with the given key/values.

type RuneHandleFunc

type RuneHandleFunc func(r rune) (handles bool, to string)

RuneHandleFunc is a function that operates on a single rune of the input string; in contrast to a StringModifierFunc. The idea is that in one iteration over the input string we can apply several handle function on each rune.

The return value should be (true, SOME_STRING) if the handle function accepts this rune and has a rule for it. In this case the function says that the rune should be replaced by SOME_STRING. It should return (false, "") if the function is not interested in the string.

Many such functions can be chained with ChainRuneHandleFuncs. The first function that returns true in such a sequence is then executed and this replacement takes place for a certain rune.

Such a rune handle function can then be converted to string modification function with RuneHandleFuncToStringModifierFunc. All runes for which no function returns true will be ignored! This means if no function ever returns true for a rune the rune will be dropped from the string (is considered invalid).

func ChainRuneHandleFuncs

func ChainRuneHandleFuncs(funcs ...RuneHandleFunc) RuneHandleFunc

ChainRuneHandleFuncs chains multiple rune functions into one, see documentation of RuneHandleFunc.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	funcs := goslugify.ChainRuneHandleFuncs(goslugify.NewSpaceReplacerFunc("-"),
		goslugify.ValidSlugRuneReplaceFunc,
	)
	modifier := goslugify.RuneHandleFuncToStringModifierFunc(funcs)
	fmt.Println(modifier("!!hello world!!"))
}
Output:

hello-world

func NewRuneHandleFuncFromMap

func NewRuneHandleFuncFromMap(m map[rune]string) RuneHandleFunc

NewRuneHandleFuncFromMap performs a replace of a single rune given a pre-defined set of replacements. This function will return (true, m[r]) for all entries in m.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	f := goslugify.NewRuneHandleFuncFromMap(map[rune]string{
		'€': "euro",
		'$': "dollar",
	})
	// without KeepAllFunc every codepoint except € and $ would be dropped
	funcs := goslugify.ChainRuneHandleFuncs(f, goslugify.KeepAllFunc)
	modifier := goslugify.RuneHandleFuncToStringModifierFunc(funcs)
	fmt.Println(modifier("The USA use $ and Germany uses €"))
}
Output:

The USA use dollar and Germany uses euro

func NewSpaceReplacerFunc

func NewSpaceReplacerFunc(replaceBy string) RuneHandleFunc

NewSpaceReplacerFunc returns a rune handle function that accepts all space runes (according to unicode.IsSpace) and replaces a space by a pre-defined string.

type SlugConfig

type SlugConfig struct {
	TruncateLength int
	WordSeparator  rune
	Form           norm.Form
	ReplaceMaps    []StringReplaceMap
	ToLower        bool
}

SlugConfig gives an easy way to build a customized slug generator.

It allows customization (instead of just using the global GenerateSlug function), but doesn't require a complete setup where you have to define a whole workflow for yourself.

For most use cases this customization should be sufficient. Just create a NewSlugConfig (this gives you the same config as the global function uses), set any of the fields on the config and then use Configure to create a SlugGenerator with the given settings.

The following fields can be adjusted:

TruncateLength: If set to a value > 0 this is the maximal length that the slug is allowed to have, smart truncating is used to truncate the string. If you want more details about truncating have a look at NewTruncateFunc. Note that this is the number of runes in th string, not the number of bytes.

WordSeparator defines which codepoint should be used to separate words in the string. For example: "foo bar" --> "foo-bar". Also multiple occurrences of this codepoint will be stripped, e.g. "foo--bar" --> "foo-bar". If the string has leading or trailing '-' separators they will be trimmed, e.g. "-foo-bar-" --> "foo-bar". This codepoint will also determine where a word begins / ends for truncating the string (if TruncateLength > 0, again see NewTruncateFunc).

Form defines the UTF-8 normal form to use, the default should do in most cases, however see https://blog.golang.org/normalization.

ReplaceMaps can be used to add your own custom replacers. They could for example contain language specific replacements. See MergeStringReplaceMaps how multiple maps are merged. This replacement takes place right after the pre processors, so they're the first step after the pre processing.

ToLower is by default set to true and the whole string is transformed to all lowercase codepoints in th pre processing phase.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	config := goslugify.NewSlugConfig()
	// set the allowed max length to 11
	config.TruncateLength = 11
	// don't convert to lower case
	config.ToLower = false
	generator := config.Configure()
	fmt.Println(generator.GenerateSlug("Hello World! Isn't this amazing?"))
}
Output:

Hello-World
Example (Second)
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	config := goslugify.NewSlugConfig()
	config.AddReplaceMap(map[string]string{
		"world": "moon",
	})
	generator := config.Configure()
	fmt.Println(generator.GenerateSlug("Hello World!!!"))
}
Output:

hello-moon

func NewSlugConfig

func NewSlugConfig() *SlugConfig

NewSlugConfig returns the default config that is used by the global GenerateSlug function, just change the fields you want to customize and call Configure.

func (*SlugConfig) AddReplaceMap

func (config *SlugConfig) AddReplaceMap(m StringReplaceMap)

AddReplaceMap add a new replace map to the back of the ReplaceMaps list.

func (*SlugConfig) Configure

func (config *SlugConfig) Configure() *SlugGenerator

Configure creates a SlugGenerator from the given config.

func (*SlugConfig) GetPhases

func (config *SlugConfig) GetPhases() (pre, processors, final []StringModifierFunc)

GetPhases returns the modifiers described by this config. You can use this function if you want to add custom modifiers by your own.

func (*SlugConfig) GetValidator

func (config *SlugConfig) GetValidator() func(s string) bool

GetValidator returns a function that validates if a string is a valid slug according to this specification. All slugs generated by Configure().GenerateSlug should by valid slugs.

One note though: As already mentioned there is not guaranteed that the specification might not change. I think in general this type should not change much, but even in the same major release new fields might be added. It should not be anything breaking the code of other people or change the default behavior, I'm just saying that the output should be used more for testing, not some hard coded assertions.

Also: This function only validates the options present in the config, if you added other modifiers yourself they, of course, will not be checked.

Also note that the replacement maps are not checked, i.e. it is not checked if a word within s could have been replaced with the replacement maps. It's more or less a syntax test, not a semantic test.

type SlugGenerator

type SlugGenerator struct {
	PreProcessor StringModifierFunc
	Processor    StringModifierFunc
	Finalizer    StringModifierFunc
}

SlugGenerator is the type that actually creates all slugs.

The conversion input --> slug is split up into three faces: Preprocessing, processing and postprocessing (PreProcessor, Processor and Finalizer).

The idea behind this is to make it easier to add your own modifiers at "the right moment". The idea is that the string passes through all three phases, each doing something different:

The pre processor prepares the string to be actually processed later. This by default includes: Remove invalid UTF-8 codepoints from the string, normalize the string to NKFC (see https://blog.golang.org/normalization) and making the string lower case.

The string is then prepared to be actually be processed: Replacements can assume that the string is valid and everything in it is lowercase.

The main phase thus is responsible to create a slug form, i.e. use only valid slug codepoints, replace strings etc. By default this processing phase will do the following: Replace all spaces (" ", newline etc.) by "-", replace all dash symbols (for example the UTF-8 ― by "-", they're different codepoints), translate umlauts like 'ä' --> "ae" or "ß" --> "ss", then drop everything that is not a valid slug codepoint.

After that the string is finalized and converted to a "normal form". By default this includes that all occurrences of more than one "-" are replaced by a single "-" and the removal of all leading / trailing "-".

There are different ways to modify the slug generator, see the project homepage at https://github.com/FabianWe/goslugify and the examples in Configure.

Of course you can also completely write your own generator by just setting all three parts yourself, but then you should know what you're doing.

An important note: It is not guaranteed that this order remains consistent over all versions of this package! Probably only more functionality will be added, but I don't make any promises that this doesn't change!

As a rule: If you need slugs for example in a database to identify objects store the slug, don't rely on the slug generator to for example compute the same slug again and again for the same input.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	slugGenerator := goslugify.NewDefaultSlugGenerator()
	fmt.Println(slugGenerator.GenerateSlug("foo bar -- hello"))
}
Output:

foo-bar-hello

func NewDefaultSlugGenerator

func NewDefaultSlugGenerator() *SlugGenerator

NewDefaultSlugGenerator returns a slug generator that consists of the components as returned by GetDefaultPreProcessors, GetDefaultProcessors and GetDefaultFinalizers.

func NewEmptySlugGenerator

func NewEmptySlugGenerator() *SlugGenerator

NewEmptySlugGenerator without any processing steps, this should only be used if you want to implement your own workflow without any of the defaults.

func (*SlugGenerator) GenerateSlug

func (gen *SlugGenerator) GenerateSlug(in string) string

GenerateSlug generates a slug by performing all three phases.

func (*SlugGenerator) Modify

func (gen *SlugGenerator) Modify(in string) string

Modify is not really required, but as a fact SlugGenerator also implements StringModifier.

func (*SlugGenerator) WithFinalizer

func (gen *SlugGenerator) WithFinalizer(modifier StringModifierFunc) *SlugGenerator

WithFinalizer adds a new finalizer to the generator. Note: If you plan to add a lot of finalizers it's probably better to append to GetDefaultFinalizers and then chain all entries yourself.

func (*SlugGenerator) WithPreProcessor

func (gen *SlugGenerator) WithPreProcessor(modifier StringModifierFunc) *SlugGenerator

WithPreProcessor adds a new pre processor to the generator. Note: If you plan to add a lot of processor it's probably better to append to GetDefaultPreProcessors and then chain all entries yourself.

func (*SlugGenerator) WithProcessor

func (gen *SlugGenerator) WithProcessor(modifier StringModifierFunc) *SlugGenerator

WithPreProcessor adds a new processor to the generator. Note: If you plan to add a lot of processor it's probably better to append to GetDefaultProcessors and then chain all entries yourself.

type StringModifier

type StringModifier interface {
	Modify(in string) string
}

StringModifier is an interface for types implementing a modification function. They can be converted to a StringModifierFunc with ToStringHandleFunc. As a StringModifierFunc implementations should not have side effects and must be safe to be called concurrently by multiple go routines.

type StringModifierFunc

type StringModifierFunc func(in string) string

StringModifierFunc is any function that takes a string and returns a modified one. These function should not have side effects, like changing variables in a closure and must be allowed to be called concurrently by multiple go routines.

Such a function takes the whole string in question and modifies it (in contrast to for example a RuneHandleFunc). These function make up most of the functionality of this library.

There is also an interface called StringModifier with a similar purpose. Such an interface instance can be converted to a modifier function by ToStringHandleFunc.

Note that many of the functions in the go string package are of this form.

func ChainStringModifierFuncs

func ChainStringModifierFuncs(funcs ...StringModifierFunc) StringModifierFunc

ChainStringModifierFuncs takes a sequence of modifier functions and returns them as a single function. This function will apply all modifiers in the order in which they are given.

func GetDefaultFinalizers

func GetDefaultFinalizers() []StringModifierFunc

GetDefaultFinalizers returns the default list of finalizers, see SlugGenerator for details. The result will contain: replace multiple occurrences of "-" by a single one, trim leading and tailing "-".

Note: There is no guarantee that these processor will always remain the same, it's probable that new ones might be added, even in the same major version (which shouldn't be a problem for most applications).

func GetDefaultPreProcessors

func GetDefaultPreProcessors() []StringModifierFunc

GetDefaultPreProcessors returns the default list of pre processors, see SlugGenerator for details. The result will contain: IgnoreInvalidUTF8, normalization to NKFC, transforming the string to lowercase codepoints.

Note: There is no guarantee that these processor will always remain the same, it's probable that new ones might be added, even in the same major version (which shouldn't be a problem for most applications).

func GetDefaultProcessors

func GetDefaultProcessors() []StringModifierFunc

GetDefaultProcessors returns th default list of processors, see SlugGenerator for details. The result will contain: Replace spaces by "-", replace dashes and hyphens by "-", translate umlauts, finally keep only the default set of codepoints and drop all others (see ValidSlugRuneReplaceFunc).

Note: There is no guarantee that these processor will always remain the same, it's probable that new ones might be added, even in the same major version (which shouldn't be a problem for most applications).

func NewReplaceMultiOccurrencesFunc

func NewReplaceMultiOccurrencesFunc(in rune) StringModifierFunc

NewReplaceMultiOccurrencesFunc returns a StringModifierFunc that will remove multiple occurrences of the same rune. For example if the separator is '-' you usually want exactly one '-' to separate word. So "foo--bar" should be transformed to "foo-bar".

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	f := goslugify.NewReplaceMultiOccurrencesFunc('-')
	fmt.Println(f("foo--bar---hello"))
}
Output:

foo-bar-hello

func NewTrimFunc

func NewTrimFunc(cutset string) StringModifierFunc

NewTrimFunc returns a new StringModifierFunc that removes all leading and trailing occurrences of cutset from a string. To be more explicit: Each codepoint in cutset will be removed, see strings.Trim. For example "-+foo-+" will be transformed to "foo" for the cutset "-+".

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	f := goslugify.NewTrimFunc("-_")
	fmt.Println(f("----hello---_"))
}
Output:

hello

func NewTruncateFunc

func NewTruncateFunc(maxLength int, wordSep string) StringModifierFunc

NewTruncateFunc returns a StringModifierFunc that will truncate the string to a given maximum length.

It will to a "smart" split, i.e. it will only take whole words and not truncate in the middle of a string. So NewTruncateFunc(5, "-")("foo-bar") will return only "foo", because "foo-bar" would be too long. As a special case the first word as defined by wordSep might be truncated in the word if it already is too long.

maxLength is the number of runes in the string, not the number of bytes.

Note: If the string starts with wordSep so may the result, so you might want to trim time string, either before or after. Also wordSep should not have multiple occurrences, otherwise the result can be a bit "strange". See some of the tests if you want to exactly know what I mean. In general NewReplaceMultiOccurrencesFunc should be called first.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	f := goslugify.NewTruncateFunc(5, "-")
	fmt.Println(f("foo-bar"))
}
Output:

foo
Example (Second)
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	f := goslugify.NewTruncateFunc(6, "+")
	fmt.Println(f("thisisaverylongword+foo"))
}
Output:

thisis
Example (Third)
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	// this is one of the "weird" cases mentioned
	f := goslugify.NewTruncateFunc(5, "-")
	fmt.Println(f("-a--foo"))
}
Output:

-a-

func RuneHandleFuncToStringModifierFunc

func RuneHandleFuncToStringModifierFunc(runeHandler RuneHandleFunc) StringModifierFunc

RuneHandleFuncToStringModifierFunc converts a rune handle function to a string modifier function, usually this is a chained function. See RuneHandleFunc documentation for details.

func ToStringHandleFunc

func ToStringHandleFunc(modifier StringModifier) StringModifierFunc

ToStringHandleFunc converts a StringModifier to a StringModifierFunc.

type StringReplaceMap

type StringReplaceMap map[string]string

StringReplaceMap describes a replacement that should take place. The keys from the map are substituted by the value of that key.

func GetLanguageMap

func GetLanguageMap(languages ...string) StringReplaceMap

GetLanguageMap returns a StringReplaceMap for a given list of languages. All maps for the specific languages are merged with MergeStringReplaceMaps. If a language doesn't exist the entry will be ignored.

Supported languages right now are "en" (English) and "de" (German).

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	config := goslugify.NewSlugConfig()
	config.AddReplaceMap(goslugify.GetLanguageMap("de"))
	generator := config.Configure()
	fmt.Println(generator.GenerateSlug("Aragorn & Arwen"))
}
Output:

aragorn-und-arwen

func MergeStringReplaceMaps

func MergeStringReplaceMaps(maps ...StringReplaceMap) StringReplaceMap

MergeStringReplaceMaps merges multiple maps into one. If an entry appears in more than one map the first occurrence of that key is used, that is maps coming later in the chain can only add new keys, not overwrite keys from previous maps.

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	m1 := map[string]string{
		"a": "b",
	}
	// the 'a' in this mapping will be ignored (because it exists already in m1)
	// 'a' will be replaced by "b", even though m2 maps 'b' --> "c"
	m2 := map[string]string{
		"a": "fooo",
		"b": "c",
		"c": "d",
	}
	combined := goslugify.MergeStringReplaceMaps(m1, m2)
	modifier := goslugify.NewConstantReplacerFromMap(combined)
	fmt.Println(modifier.Modify("abcde"))
}
Output:

bcdde

type UTF8Normalizer

type UTF8Normalizer struct {
	Form norm.Form
}

UTF8Normalizer implements StringModifier, the string is normalized according to utf-8 normal forms. For details see the norm package https://godoc.org/golang.org/x/text/unicode/norm and this blog post https://blog.golang.org/normalization.

The default form used in this package is NFKC. It is usually called right after IgnoreInvalidUTF8.

func NewUTF8Normalizer

func NewUTF8Normalizer(form norm.Form) UTF8Normalizer

NewUTF8Normalizer returns a new normalizer given the form.

func (UTF8Normalizer) Modify

func (normalizer UTF8Normalizer) Modify(in string) string

type WordReplacer

type WordReplacer struct {
	WordMap       StringReplaceMap
	WordSeparator string
}

WordReplacer replaces occurrences of words within a string, it implements StringModifier. The difference between WordReplacer and ConstantReplacer is that WordReplacer does not replace all occurrences, but only complete words. A word is defined by splitting the string given the WordSeparator.

So a replacement "@" --> "at" would behave on the string "something@-@" differently: ConstantReplacer would return "somethingat-at" and WordReplacer would return "something@-at" (given that the separator is "-").

Example
package main

import (
	"fmt"
	"github.com/FabianWe/goslugify"
)

func main() {
	replacer := goslugify.NewWordReplacer(map[string]string{
		"@": "at",
	}, "-")
	fmt.Println(replacer.Modify("something@-@"))
}
Output:

something@-at

func NewWordReplacer

func NewWordReplacer(wordMap StringReplaceMap, wordSeparator string) *WordReplacer

NewWordReplacer returns a new replacer given the replacement map and the word separator.

func (*WordReplacer) Modify

func (replacer *WordReplacer) Modify(in string) string

Jump to

Keyboard shortcuts

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