GNU grep doesn't have look-arounds either. It does have back-references, but that doesn't impact searches that don't use back-references.
I don't think there is really a concise way to describe why ripgrep is faster when comparing apples-to-apples. It depends on the queries and the corpus. The primary reasons are that it makes more efficient use of the hardware with algorithms that utilize SIMD.
If you do an apples-to-oranges comparison (i.e., "why is `rg foo ./` so much faster than `grep -r foo ./`), then the answer is pretty easily "because ripgrep uses parallelism and employs smart filtering by default."
I said out loud, "Wow" and browsed through ripgrep. Nice work!
Was torn on whether you were tailing the HN api with ripgrep to alert you or if it was just the right place and time. I had a good time going through how that would work, so, thank you haha!
Occam's razor, right?
I do occasionally manually search HN for mentions of ripgrep. But that wasn't how I found this thread.
To put it another way, do you think you could've written ripgrep in another language? In C? In C++? In Go?
As for Go, I don't know. The garbage collector seems likely to be a problem. Ben Boyter wrote about working on a similarish tool in Go and problems with the GC: https://boyter.org/posts/sloc-cloc-code-performance/
At the very least, such a tool in Go would probably require writing your own regex engine if you want to get comparable performance. (You can see how similar tools in Go, such as pt and sift, fall off a performance cliff as soon as you lean too heavily on the regex engine.) Or at the very least, contribute back to Go's standard library and make `regexp` faster. Whether it can match the speed of a Rust/C/C++ regex engine, I don't know. It's an open question I think.
My own experience w/ Rust is limited to just kicking the tires implementing my favorite toy problem, but it was incredibly positive -- my solution ended up faster than my previous best (in C++) while also having extremely-straightforward, clean code.
(Something that particularly blew my mind was crossbeam_channel being (arguably) nicer than Go's built-in channels, and being able to spread work over threads w/ zero possibility of races -- that's some fuckin' cool shit.)
That experience, combined w/ observation of tools like fd and ripgrep, have convinced me that rust is actually unlocking a higher level of quality for software, at least in practice, if not in theory.
Your answer has not disabused me of the perception! :-)
> Although of course there are alternatives to ripgrep written in C or C++, so I'm not sure how compelling of an argument that is.
But they're not as good as ripgrep ;-)
I would naturally agree, but my users make that argument far better than I can. :-)
Why don't most grep utilities just do the obvious right thing and support searches on .c* or .h or .txt or whatever? (HN is mangling the text, but you can read the above as "star dot c star," "star dot h," or "star dot txt.")
I've done a lot of work to make ripgrep work well on Windows. But haven't done this. You can usually work around it pretty easily with the -g flag. e.g.,
rg foo -g '*.{c,h}'
or even shorter rg foo -tcI'm basically looking to maintain the same functionality that was available under DOS with Borland's Turbo Grep in the late 1980s. Those old DOS function calls are still emulated in Win32 as far as I know, but a current implementation would normally use FindFirstFile / FindNextFile like so:
C8 name_buffer[MAX_PATH];
strcpy(name_buffer,dir_buffer); // directory to scan, if not CWD
strcat(name_buffer,filespec); // MS-DOS style filespec with optional * and/or ? wildcards (obviously use snprintf, etc. for this, not strcpy/strcat)
HANDLE search_handle;
WIN32_FIND_DATA found;
search_handle = FindFirstFile(name_buffer, &found);
if (search_handle != INVALID_HANDLE_VALUE)
{
do
{
if (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
continue;
}
strcpy(name_buffer, dir_buffer);
strcat(name_buffer, found.cFileName);
// name_buffer now indicates a single file
// which can be opened with fopen or
// CreateFile or whatever
}
while (FindNextFile(search_handle, &found));
FindClose(search_handle);
}
There's probably already some code like this in the area of the program that's used to implement the -g mechanism for types. The latter seems a bit overengineered when I'm just looking for wildcard expansion, but I can see it being useful in a lot of cases. It just shouldn't be the only way to constrain the file set, IMO. A new syntax isn't expected or desired, at least not by me, as long as the old one works.