Skip to main content
1 of 4
Dennis
  • 210.6k
  • 41
  • 370
  • 825

Pushing concatenated character ranges

  • The uppercase ASCII letters (A-Z) can be pushed as

      '[,65>
    

    which generates the string of all characters up to Z, then discards the first 65 (up to @).

  • All ASCII letters (A-Za-z) can be pushed as

      '[,65>_el+
    

    which works as above, then creates a copy, converts to lowercase and appends.

    But there's a shorter way to do it!

    Then often overlooked ^ operator (symmetric differences for lists) allows to create the same ranges while saving three bytes:

      '[,_el^
    

    '[, creates the range of all ASCII characters up to z, _el creates a lowercase copy and ^ keep only characters of both strings that appear in one but not both.

    Since all letters in the first string are uppercase, all in the second are lowercase and all non-letter characters are in both strings, the result in the string of letters.

  • The RFC 1642 Base64 alphabet (A-Za-z0-9+/) can be pushed using the above technique and appending the non-letters:

      '[,_el^A,s+"+/"+
    

    An equally short way of pushing this string makes use solely of symmetric differences:

      "+,/0:[a{A0":,:^
    

    How can we find the string at the beginning?

    All used character ranges (A-Z, a-z, 0-9, +, /) can be pushed as the symmetric difference of to range that start at the null byte, namely 'A,'[,^, 'a,'{,^, '0,':,^, '+,',,^ and '/,'0,^.

    Therefore, executing :,:^ on "A[a{):+,/0" will push the desired characters, but not in the right order.

    How do we find the right order? Brute force to the rescue! The program

      "0:A[a{+,/0"e!
      {:,:^"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"=}=
    

    iterates over all possible permutations of the string, applies :,:^ and compares the result to the desired output.

  • The radix-64 alphabet used, e.g, by crypt (.-9A-Za-z) can be generated using the above method:

      ".:A[a{":,:^
    

    This is the shortest method I know.

    Since all characters in the desired output are in ASCII order, iterating over permutations isn't needed.

  • Not all concatenated character ranges can be pushed in the desired order using :,:^.

    (Examples and workarounds to be added.)

Dennis
  • 210.6k
  • 41
  • 370
  • 825