Code Monkey home page Code Monkey logo

fuzzy's Introduction

gopher looking for stuff gopher found stuff

fuzzy

Build Status Documentation

Go library that provides fuzzy string matching optimized for filenames and code symbols in the style of Sublime Text, VSCode, IntelliJ IDEA et al. This library is external dependency-free. It only depends on the Go standard library.

Features

  • Intuitive matching. Results are returned in descending order of match quality. Quality is determined by:

    • The first character in the pattern matches the first character in the match string.
    • The matched character is camel cased.
    • The matched character follows a separator such as an underscore character.
    • The matched character is adjacent to a previous match.
  • Speed. Matches are returned in milliseconds. It's perfect for interactive search boxes.

  • The positions of matches are returned. Allows you to highlight matching characters.

  • Unicode aware.

Demo

Here is a demo of matching various patterns against ~16K files from the Unreal Engine 4 codebase.

demo

You can run the demo yourself like so:

cd _example/
go get github.com/jroimartin/gocui
go run main.go

Usage

The following example prints out matches with the matched chars in bold.

package main

import (
	"fmt"

	"github.com/sahilm/fuzzy"
)

func main() {
	const bold = "\033[1m%s\033[0m"
	pattern := "mnr"
	data := []string{"game.cpp", "moduleNameResolver.ts", "my name is_Ramsey"}

	matches := fuzzy.Find(pattern, data)

	for _, match := range matches {
		for i := 0; i < len(match.Str); i++ {
			if contains(i, match.MatchedIndexes) {
				fmt.Print(fmt.Sprintf(bold, string(match.Str[i])))
			} else {
				fmt.Print(string(match.Str[i]))
			}
		}
		fmt.Println()
	}
}

func contains(needle int, haystack []int) bool {
	for _, i := range haystack {
		if needle == i {
			return true
		}
	}
	return false
}

If the data you want to match isn't a slice of strings, you can use FindFrom by implementing the provided Source interface. Here's an example:

package main

import (
	"fmt"

	"github.com/sahilm/fuzzy"
)

type employee struct {
	name string
	age  int
}

type employees []employee

func (e employees) String(i int) string {
	return e[i].name
}

func (e employees) Len() int {
	return len(e)
}

func main() {
	emps := employees{
		{
			name: "Alice",
			age:  45,
		},
		{
			name: "Bob",
			age:  35,
		},
		{
			name: "Allie",
			age:  35,
		},
	}
	results := fuzzy.FindFrom("al", emps)
	for _, r := range results {
		fmt.Println(emps[r.Index])
	}
}

Check out the godoc for detailed documentation.

Installation

go get github.com/sahilm/fuzzy or use your favorite dependency management tool.

Speed

Here are a few benchmark results on a normal laptop.

BenchmarkFind/with_unreal_4_(~16K_files)-4         	     100	  12915315 ns/op
BenchmarkFind/with_linux_kernel_(~60K_files)-4     	      50	  30885038 ns/op

Matching a pattern against ~60K files from the Linux kernel takes about 30ms.

Contributing

Everyone is welcome to contribute. Please send me a pull request or file an issue. I promise to respond promptly.

Credits

  • @ericpauley & @lunixbochs contributed Unicode awareness and various performance optimisations.

  • The algorithm is based of the awesome work of forrestthewoods. See this blog post for details of the algorithm.

  • The artwork is by my lovely wife Sanah. It's based on the Go Gopher.

  • The Go gopher was designed by Renee French (http://reneefrench.blogspot.com/). The design is licensed under the Creative Commons 3.0 Attributions license.

License

The MIT License (MIT)

Copyright (c) 2017 Sahil Muthoo

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

fuzzy's People

Contributors

caarlos0 avatar dvrkps avatar ericpauley avatar lunixbochs avatar sahilm avatar santosh653 avatar talkaminker avatar vlad-stoian avatar waitak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fuzzy's Issues

Errors in the demo example

The initialization of g is
g, err = gocui.NewGui(gocui.OutputNormal)
instead of
g, err := gocui.NewGui(gocui.OutputNormal)

The usage of g in the finder function gives an error saying g is undefined as g is declared in the main function.

would this make a good spell checker?

Wondering if this lib could be used for spell checking? I know the algorithms for spell checkers can be much different than your classic auto complete fuzzy search jam, so just curious.

Request for New Tag (v0.1.1)

Some Debian packages have been utilizing the functionality provided by the fuzzy library and recently came across a commit that I believe would greatly benefit the community.

Specifically, I am referring to the commit with the hash c48e322 that adds the feature feat: fuzzy find without sorting.

Would it be possible for you to create a new tag like v0.1.1 on the repository?

This would facilitate easier referencing and usage by other developers who rely on your library within the Debian ecosystem.

Your assistance would contribute integration of the fuzzy library within Debian packaging.

Thank you for your time and consideration.

Add option to ignore spaces?

Would it be difficult to add an option to have fuzzy.Find() ignore spaces?

This would be nice to normalize the behavior with fzf.

For example, if I am searching through a bunch of filepaths, I will sometimes type part of one directory name, , and then a part of some other directory name or the filename.

In this sense, you are sort of passing in fragments to be matched, and the spaces are just being used to separate the fragments.

I saw that there was another similar issue requesting support to allow the order to be ignored, which is indeed how fzf operates, but even if the method still expects search phrases to be provided order, this would still be useful, imo.

Thanks for taking the time to put this library together and share it with the community! It works really well overall and was quite simple to pick up and use.

Strings with spaces

Been using fuzzy for my react autocomplete component and its working very good. Is it possible to tweak fuzzy to ignore the order of words when there are spaces? If I'm searching for "duct tape" I can't find the result when I search "tape duct".

Copywriting

Hello!

I've been watching your project and I want to make the copywriting stuff: Contact Us, About Us, FAQ, etc

Best Regards!

'\' as separator?

Looks like this uses only '/' as separator - but for windows, using just '' or both '' and '/' as separators will lead to better results

FindFrom return another struct value?

Fairly new to go, just have a question about the FindFrom function.

  1. Using the README example, is it possible to return the "age" field with the result?

Edit: After playing with it a bit more...

  1. I am trying to use this as an auto complete in a react app. I noticed when imputing a quotation mark, on my computer it is U+0022 (Standard straight quotation mark) but when entering on my phone the value is U+201D โ€ (Right double quotation mark) and the search on my phone will not match my data. Would if be worth it to make U+0022,U+201C,U+201D equal when searching?

  2. Is there a more elegant way to limit the search results than this? maybe the FindFrom function could have a functional option to limit the result?

	r := results.Len()
	if r > 10 {
		r = 10
	}
	results = results[:r]

Scoring - implement score based on length of gaps between matched letter?

So this is a suggestion/question. The readme indicates that

The matched character is adjacent to a previous match.

This works in the following case - search string of blog
image

However, if I now type rpy so that the search string is blogrpy then
image

In this case, the first match has all the characters - but its obvious that it's of lesser quality.

I'm not sure how the adjacency scoring is implemented but could do something with sum of number of letters between matches? Something which has a higher number of letters between matched chars gets a lower score.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.