**Use case**

I want to estimate better parameters for fulltext (`ngrambf_v1`) index.

**Describe the solution you'd like**

Implement it as SQL function:

`ngrams(string, N)`

that returns array of FixedString.

**Describe alternatives you've considered**

It can be done with less efficient and more cumbersome way:

```
WITH 3 AS n, extractAll(text, '.') AS chars 
SELECT 
  arrayMap(x -> arrayStringConcat(x), 
    arrayFilter(x -> length(x) = n, 
      arrayMap(x, i -> arraySlice(chars, i, n), 
        chars, arrayEnumerate(chars)))) AS ngrams
```

**Additional context**

`ngramsUTF8` can also be implemented to extract ngrams of Unicode code points.
{
    *token_start = *pos;
    *token_len = 0;
    size_t code_points = 0;
    for (; code_points < n && *token_start + *token_len < len; ++code_points)
    {
        size_t sz = UTF8::seqLength(static_cast<UInt8>(data[*token_start + *token_len]));
        *token_len += sz;
    }
    *pos += UTF8::seqLength(static_cast<UInt8>(data[*pos]));
    return code_points == n;
}
bool NgramTokenExtractor::nextLike(const String & str, size_t * pos, String & token) const
{
    token.clear();
    size_t code_points = 0;
    bool escaped = false;
    for (size_t i = *pos; i < str.size();)
    {
        if (escaped && (str[i] == '%' || str[i] == '_' || str[i] == '\\'))
        {
            token += str[i];
            ++code_points;
            escaped = false;
            ++i;
        }
        else if (!escaped && (str[i] == '%' || str[i] == '_'))