Is it possible to base 36 encode with JavaScript / jQuery?

后端 未结 4 2035
臣服心动
臣服心动 2021-01-31 18:00

I\'m thinking about using the encode/decode technique here (Encoding to base 36/decoding from base 36 is simple in Ruby)

how to implement a short url like urls in twitte

相关标签:
4条回答
  • 2021-01-31 18:24

    I wrote this baseXY shortener, designed for a very similar question/need I had:

    https://github.com/marko-36/base29-shortener.

    • By default, in order to leave out easily interchangeable characters, it is a base29 shortener, but the 'XY' number is the same as number of characters you decide to use for encoding.
    • Since the set of characters is fully customizable, you can omit any you wish (i, l, 1, L, o, 0, O..)
    • To make it less obvious, what the encoding character set is, and/or if you want the encoding string to have a minimal length, just start encoding from a high enough number.

    This is it, hope it helps:

        const c=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7', '8', '9']; 
        //characters for encoding
    
        function to29(i){
            var sLen = Math.floor(Math.log(i)/Math.log(c.length)) +1;
            var s = '';
            for(ex=sLen-1; ex>-1; --ex){
                s += c[Math.floor(i / Math.pow(c.length,ex))];
                i = [i % Math.pow(c.length,ex)];
            }
            return s;
        }
    
        function from29(s){
            var i = 0;
            for (ex=0; ex<s.length; ++ex){
                i += c.indexOf(s.substring(ex,ex+1))*Math.pow(c.length,s.length-1-ex);
            }
            return i;
        }
    
    0 讨论(0)
  • 2021-01-31 18:25

    For anyone looking to decode @imjosh's answer in python (say if you've encoded client-side and need to decode server-side), this is what I used. I would have left as a comment in @imjosh's answer but comments don't format very well.

    def decodeBase36(str):
      decoded_str = ""
      for i in range(0, len(str), 2):
        char = chr(int(str[i:i+2], 36))
        decoded_str += char
      return decoded_str
    

    and a not-as-elegant Objective-C version:

    + (NSString *)b36DecodeString:(NSString *)b36String
    {
        NSMutableString *decodedString = [NSMutableString stringWithFormat:@""];
        for (int i = 0; i < [b36String length]; i+=2) {
            NSString *b36Char = [b36String substringWithRange:NSMakeRange(i, 2)];
            int asciiCode = 0;
            for (int j = 0; j < 2; j++) {
                int v = [b36Char characterAtIndex:j];
                asciiCode += ((v < 65) ? (v - 48) : (v - 97 + 10)) * (int)pow(36, 1 - j);
            }
            [decodedString appendString:[NSString stringWithFormat:@"%c", asciiCode]];
        }
        return decodedString;
    }
    
    0 讨论(0)
  • 2021-01-31 18:27

    The toString method on Number has an optional argument of radix:

    (128482).toString(36);
    128482..toString(36);
    128482 .toString(36);
    var num = 128482; num.toString(36);
    

    Note this doesn't work, because numbers expect decimal digits after a period, not letters:

    128482.toString(36);  // Syntax error
    

    Also, you can decode with JS as well:

    parseInt("2r4y", 36);
    

    EDIT:

    But if I want to remove look-alike characters (1-l or 0-O) what can I do?

    The easiest is to reduce the base by number of characters you're skipping, then make a translation: Note that only one of 1-l or 0-O is a problem, since base36 encodes only lowercase (in which case you have 1-l, but not 0-O) which you can make uppercase (in which case, vice versa).

    (128482).toString(36).replace(/[m-y]/, x => String.fromCharCode(x.charCodeAt(0) + 1))
    

    If you want to have a base larger than 36, you would have to have your own base-changing function, as 36 is as high as toString supports. In that case, it is easy enough to make your own digit inventory as you want.

    for working with long numbers?

    Go ahead :) Note the n suffix that turns the number into BigInt:

    1000000000000000000000000000000000000000000000000000000000n.toString(36)
    // => "9edwccv83mch429oxmlxupo4z1bdaiusrm29s"
    
    0 讨论(0)
  • 2021-01-31 18:34

    For anyone looking for how to encode a string in base36 (since this question, How do i convert string to base36 in javascript , is redirected here) -

    Here's what I came up with.

    /* encode / decode strings to / from base36 
    
       based on: http://snipplr.com/view/12653/
    */
    
    var base36 = {
        encode: function (str) {
            return Array.prototype.map.call(str, function (c) {
                return c.charCodeAt(0).toString(36);
            }).join("");
        },
        decode: function (str) {
            //assumes one character base36 strings have been zero padded by encodeAscii
            var chunked = [];
            for (var i = 0; i < str.length; i = i + 2) {
                chunked[i] = String.fromCharCode(parseInt(str[i] + str[i + 1], 36));
            }
            return chunked.join("");
        },
        encodeAscii: function (str) {
            return Array.prototype.map.call(str, function (c) {
                var b36 = base36.encode(c, "");
                if (b36.length === 1) {
                    b36 = "0" + b36;
                }
                return b36;
            }).join("")
        },
        decodeAscii: function (str) {
            //ignores special characters/seperators if they're included
            return str.replace(/[a-z0-9]{2}/gi, function (s) {
                return base36.decode(s);
            })
        }
    };
    
    var foo = "a-Az-Z 0-9 !@#$%^&*()-_=+[{]};:',<.>/?`~";
    var bar = base36.encodeAscii(foo);
    
    console.log(foo);
    console.log(base36.decode(bar));
    
    console.log('');
    
    var bar = "==/" + bar + "\\==";
    console.log(bar)
    console.log(base36.decodeAscii(bar));
    
    
    //doesn't work
    console.log('');
    var myString = "some string";
    var myNum = parseInt(myString, 36);
    console.log(myNum.toString(36))
    
    myString = "FooBarW000t";
    myNum = parseInt(myString, 36);
    console.log(myNum.toString(36))
    
    myString = "aAzZ09!@#$%^&*()-_=+[{]};:',<.>/?`~";
    myNum = parseInt(myString, 36);
    console.log(myNum.toString(36))
    
    /* 
    Outputs:
    
    a-Az-Z 0-9 !@#$%^&*()-_=+[{]};:',<.>/?`~
    a-Az-Z 0-9 !@#$%^&*()-_=+[{]};:',<.>/?`~
    
    ==/2p191t3e192i0w1c191l0w0x1s0z10112m12161415192n1p172j3f2l3h1n1m13181o1a1q1b1r2o3i\==
    ==/a-Az-Z 0-9 !@#$%^&*()-_=+[{]};:',<.>/?`~\==
    
    some
    foobarw000w
    aazz09
    */
    
    0 讨论(0)
提交回复
热议问题