The "algorithm" for generating these filters is not publicly available, although some information about how the strings are constructed is known. Allow me to heavily quote from Kevin Montrose's blog:
"Filters, at their core, ended up being a simple bitfield of which fields to include in a response."
So basically, the filter string is an ASCII representation of a bitfield containing information about what the filter includes and its "safe" attribute.
However, the following statement (which I strongly agree with) provides a clear explanation as to why you should avoid any attempt to reverse engineer the strings:
"The point of bit shuffling is to make it both harder to figure out the implementation (though naturally not impossible, the average developer is more than bright enough to figure our scheme out given enough time) so such “too clever for your own good” behavior is harder to pull off, and to really drive the point home that you shouldn’t be creating filters without calling /filter/create."
I see no reason why you would want to avoid calling /filter/create
since it is simple, fast, and only needs to be done once.