Ответ 1
Самый простой способ:
- сохранить базу данных всех URL-адресов
- когда вы вставляете новый URL-адрес в базу данных, узнайте идентификатор первичного ключа с автоматическим инкрементным целым.
- закодировать это целое число на основание 36 или 62 (цифры + строчные буквы альфа или цифры + смешанный регистр). Вуаля! У вас короткий URL-адрес!
Кодирование на основание 36/декодирование с базы 36 в Ruby прост:
12341235.to_s(36)
#=> "7cik3"
"7cik3".to_i(36)
#=> 12341235
Кодировка на базу 62 немного сложнее. Вот один из способов сделать это:
module AnyBase
ENCODER = Hash.new do |h,k|
h[k] = Hash[ k.chars.map.with_index.to_a.map(&:reverse) ]
end
DECODER = Hash.new do |h,k|
h[k] = Hash[ k.chars.map.with_index.to_a ]
end
def self.encode( value, keys )
ring = ENCODER[keys]
base = keys.length
result = []
until value == 0
result << ring[ value % base ]
value /= base
end
result.reverse.join
end
def self.decode( string, keys )
ring = DECODER[keys]
base = keys.length
string.reverse.chars.with_index.inject(0) do |sum,(char,i)|
sum + ring[char] * base**i
end
end
end
... и здесь он находится в действии:
base36 = "0123456789abcdefghijklmnopqrstuvwxyz"
db_id = 12341235
p AnyBase.encode( db_id, base36 )
#=> "7cik3"
p AnyBase.decode( "7cik3", base36 )
#=> 12341235
base62 = [ *0..9, *'a'..'z', *'A'..'Z' ].join
p AnyBase.encode( db_id, base62 )
#=> "PMwb"
p AnyBase.decode( "PMwb", base62 )
#=> 12341235
Edit
Если вы хотите избежать URL-адресов, которые являются английскими словами (например, четырехсловными ругательствами), вы можете использовать набор символов, которые не включают гласные:
base31 = ([*0..9,*'a'..'z'] - %w[a e i o u]).join
base52 = ([*0..9,*'a'..'z',*'A'..'Z'] - %w[a e i o u A E I O U]).join
Однако при этом у вас все еще есть проблемы вроде AnyBase.encode(328059,base31)
или AnyBase.encode(345055,base31)
или AnyBase.encode(450324,base31)
. Таким образом, вы можете также избегать чисел, похожих на гласные:
base28 = ([*'0'..'9',*'a'..'z'] - %w[a e i o u 0 1 3]).join
base49 = ([*'0'..'9',*'a'..'z',*'A'..'Z'] - %w[a e i o u A E I O U 0 1 3]).join
Это также позволит избежать проблемы "Является ли это 0 или O?"? и "Это 1 или я?".