Desejo criar um serviço de encurtador de URL em que você possa gravar um URL longo em um campo de entrada e o serviço encurte o URL para " http://www.example.org/abcdef
".
Em vez de " abcdef
", pode haver qualquer outra sequência com seis caracteres a-z, A-Z and 0-9
. Isso torna 56 a 57 bilhões de strings possíveis.
Minha abordagem:
Eu tenho uma tabela de banco de dados com três colunas:
- id, número inteiro, incremento automático
- long, string, o URL longo digitado pelo usuário
- short, string, o URL encurtado (ou apenas os seis caracteres)
Em seguida, insiro o URL longo na tabela. Depois, selecionaria o valor de incremento automático para " id
" e criaria um hash. Esse hash deve ser inserido como " short
". Mas que tipo de hash devo construir? Algoritmos de hash como MD5 criam seqüências muito longas. Eu não uso esses algoritmos, eu acho. Um algoritmo auto-construído também funcionará.
Minha ideia:
Para " http://www.google.de/
", obtenho o ID de incremento automático 239472
. Então, eu faço os seguintes passos:
short = '';
if divisible by 2, add "a"+the result to short
if divisible by 3, add "b"+the result to short
... until I have divisors for a-z and A-Z.
Isso pode ser repetido até que o número não seja mais divisível. Você acha que essa é uma boa abordagem? Você tem uma ideia melhor?
Devido ao interesse contínuo neste tópico, publiquei uma solução eficiente para o GitHub , com implementações para JavaScript , PHP , Python e Java . Adicione suas soluções, se quiser :)
encode()
edecode()
funções. As etapas são, portanto: (1) Salvar URL no banco de dados (2) Obter ID de linha exclusivo para esse URL do banco de dados (3) Converter o número inteiro em string curta comencode()
, por exemplo,273984
paraf5a4
(4) Use a string curta (por exemplof4a4
) em seu URLs compartilháveis (5) Ao receber uma solicitação de uma sequência curta (por exemplo20a8
), decodifique a sequência para um ID inteiro comdecode()
(6) Procure URL no banco de dados para o ID fornecido. Para conversão, use: github.com/delight-im/ShortURLRespostas:
Eu continuaria sua abordagem "converter número em string". No entanto, você perceberá que o algoritmo proposto falhará se o seu ID for primo e maior que 52 .
Bases teóricas
Você precisa de uma função bijetiva f . Isso é necessário para que você possa encontrar uma função inversa g ('abc') = 123 para sua função f (123) = 'abc' . Isso significa:
Como converter o ID em um URL reduzido
[a-zA-Z0-9]
. Contém 62 letras .Pegue uma chave numérica exclusiva gerada automaticamente (o incremento automático
id
de uma tabela MySQL, por exemplo).Neste exemplo, usarei 125 10 (125 com uma base de 10).
Agora você deve converter 125 10 para X 62 (base 62).
125 10 = 2 × 62 1 + 1 × 62 0 =
[2,1]
Isso requer o uso de divisão inteira e módulo. Um exemplo de pseudo-código:
Agora mapeie os índices 2 e 1 para o seu alfabeto. É assim que seu mapeamento (com uma matriz por exemplo) pode parecer:
Com 2 → ce 1 → b, você receberá cb 62 como o URL abreviado.
Como resolver um URL reduzido para o ID inicial
O inverso é ainda mais fácil. Você acabou de fazer uma pesquisa inversa no seu alfabeto.
e9a 62 será resolvido como "quarta, 61 e 0a letra do alfabeto".
e9a 62 =
[4,61,0]
= 4 × 62 2 + 61 × 62 1 + 0 × 62 0 = 19158 10Agora encontre seu registro no banco de dados
WHERE id = 19158
e faça o redirecionamento.Implementações de exemplo (fornecidas por comentaristas)
fonte
3792586=='F_ck'
com u no lugar de _). Eu excluiria alguns caracteres como u / U para minimizar isso.Por que você gostaria de usar um hash?
Você pode apenas usar uma tradução simples do seu valor de incremento automático para um valor alfanumérico. Você pode fazer isso facilmente usando algumas conversões básicas. Digamos que o espaço de caracteres (AZ, az, 0-9 etc.) tenha 40 caracteres, converta o ID em um número de base 40 e use os caracteres como dígitos.
fonte
fonte
Não é uma resposta para sua pergunta, mas eu não usaria URLs encurtados que diferenciam maiúsculas de minúsculas. Eles são difíceis de lembrar, geralmente ilegíveis (muitas fontes tornam 1 e 1, 0 e O e outros caracteres muito semelhantes, quase impossíveis de distinguir) e propensos a erros. Tente usar apenas letras minúsculas ou maiúsculas.
Além disso, tente ter um formato no qual você misture os números e caracteres de uma forma predefinida. Existem estudos que mostram que as pessoas tendem a se lembrar de uma forma melhor do que outras (pense em números de telefone, onde os números estão agrupados em uma forma específica). Tente algo como num-char-char-num-char-char. Eu sei que isso diminuirá as combinações, especialmente se você não tiver maiúsculas e minúsculas, mas seria mais utilizável e, portanto, útil.
fonte
Minha abordagem: pegue o ID do banco de dados e, em seguida, o Base36 o codifique . Eu NÃO usaria letras maiúsculas e minúsculas, porque isso torna a transmissão desses URLs por telefone um pesadelo, mas é claro que você poderia estender facilmente a função para ser um decodificador / en base de 62.
fonte
Aqui está minha classe PHP 5.
fonte
Uma solução Node.js e MongoDB
Como sabemos o formato que o MongoDB usa para criar um novo ObjectId com 12 bytes.
Exemplo (escolho uma sequência aleatória) a1b2c3d4e5f6g7h8i9j1k2l3
Como o contador será único se estivermos armazenando os dados na mesma máquina, podemos obtê-los sem dúvida de que serão duplicados.
Portanto, o URL curto será o contador e aqui está um trecho de código supondo que seu servidor esteja funcionando corretamente.
fonte
Versão c #:
fonte
Você pode fazer o hash do URL inteiro, mas se quiser apenas diminuir o ID, faça o que Marcel sugeriu. Eu escrevi esta implementação Python:
https://gist.github.com/778542
fonte
Continuo incrementando uma sequência inteira por domínio no banco de dados e uso Hashids para codificar o número inteiro em um caminho de URL.
Eu executei um script para ver quanto tempo leva até esgotar o tamanho dos caracteres. Para seis caracteres, ele pode
164,916,224
criar links e depois subir para sete caracteres. Bitly usa sete caracteres. Menos de cinco caracteres me parecem estranhos.Hashids podem decodificar o caminho da URL de volta para um número inteiro, mas uma solução mais simples é usar o link curto inteiro
sho.rt/ka8ds3
como chave primária.Aqui está o conceito completo:
fonte
Se você não quiser reinventar a roda ... http://lilurl.sourceforge.net/
fonte
fonte
Aqui está a minha versão para quem precisar.
fonte
Por que não apenas traduzir seu ID para uma string? Você só precisa de uma função que mapeie um dígito entre, digamos, 0 e 61 para uma única letra (maiúscula / minúscula) ou dígito. Em seguida, aplique isso para criar, digamos, códigos de 4 letras, e você terá 14,7 milhões de URLs cobertos.
fonte
Aqui está uma função de codificação de URL decente para PHP ...
fonte
Não sei se alguém achará isso útil - é mais um método 'hack n slash', mas é simples e funciona bem se você deseja apenas caracteres específicos.
fonte
Você omitiu O, 0 e i de propósito?
Acabei de criar uma classe PHP baseada na solução de Ryan.
fonte
Dê uma olhada em https://hashids.org/ , é de código aberto e em vários idiomas.
A página deles descreve algumas das armadilhas de outras abordagens.
fonte
Isto é o que eu uso:
É muito rápido e pode levar números inteiros longos.
fonte
Para um projeto semelhante, para obter uma nova chave, eu faço um wrapper funcionar em torno de um gerador de string aleatório que chama o gerador até obter uma string que ainda não tenha sido usada na minha hashtable. Esse método diminuirá quando o espaço para nome começar a ficar cheio, mas como você disse, mesmo com apenas 6 caracteres, você terá muito espaço para trabalhar.
fonte
Tenho uma variante do problema, pois armazeno páginas da Web de muitos autores diferentes e preciso impedir a descoberta de páginas por adivinhação. Portanto, meus URLs curtos adicionam alguns dígitos extras à string Base-62 para o número da página. Esses dígitos extras são gerados a partir de informações no próprio registro da página e garantem que apenas 1 em 3844 URLs sejam válidas (considerando a Base 62 de 2 dígitos). Você pode ver uma descrição geral em http://mgscan.com/MBWL .
fonte
Resposta muito boa, eu criei uma implementação Golang do bjf:
Hospedado no github: https://github.com/xor-gate/go-bjf
fonte
fonte
Implementação em Scala:
Exemplo de teste com o teste Scala:
fonte
Função baseada na classe Xeoncross
fonte
Aqui está uma implementação do Node.js. que provavelmente bit.ly. gerar uma cadeia de sete caracteres altamente aleatória.
Ele usa a criptografia Node.js para gerar um conjunto de caracteres 25 altamente aleatório, em vez de selecionar aleatoriamente sete caracteres.
fonte
Minha versão do Python 3
fonte
Para obter uma solução de qualidade Node.js / JavaScript, consulte o módulo de identificação-encurtador , que é exaustivamente testado e usado na produção há meses.
Ele fornece um encurtador de ID / URL eficiente, apoiado por armazenamento conectável com o padrão Redis , e você pode até personalizar seu conjunto de caracteres de ID curto e se o encurtamento é ou não idempotente . Essa é uma distinção importante que nem todos os encurtadores de URL levam em consideração.
Em relação a outras respostas aqui, este módulo implementa a excelente resposta aceita de Marcel Jackwerth acima.
O núcleo da solução é fornecido pelo seguinte snippet do Redis Lua :
fonte
Por que não gerar uma sequência aleatória e anexá-la ao URL base? Esta é uma versão muito simplificada de fazer isso em c # .
Em seguida, basta adicionar a sequência aleatória à baseURL:
Lembre-se de que esta é uma versão muito simplificada de fazer isso e é possível que o método RandomString possa criar seqüências de caracteres duplicadas. Na produção, você deve considerar as seqüências de caracteres duplicadas para garantir que sempre tenha um URL exclusivo. Eu tenho algum código que leva em conta seqüências de caracteres duplicadas, consultando uma tabela de banco de dados que eu poderia compartilhar se alguém estiver interessado.
fonte
Este é o meu pensamento inicial, e mais pensamentos podem ser feitos, ou alguma simulação pode ser feita para verificar se funciona bem ou se é necessária alguma melhoria:
Minha resposta é lembrar a URL longa no banco de dados e usar o ID
0
para9999999999999999
(ou por maior que seja o número necessário).Mas o ID 0 para
9999999999999999
pode ser um problema, porqueA
-Z
a
-z
0
-9
_
e-
)0
de9999999999999999
uniformemente, em seguida, os hackers podem visitá-los nessa ordem e saber o que URLs pessoas estão enviando uns aos outros, por isso pode ser uma questão de privacidadeNós podemos fazer isso:
0
para999
um servidor, o Servidor A, agora o Servidor A possui 1000 desses IDs. Portanto, se houver 20 ou 200 servidores constantemente querendo novos IDs, ele não precisará continuar pedindo cada novo ID, mas sim pedindo 1000 IDs uma vez.000...00000001
torna-se10000...000
, de modo que, quando convertido em base64, aumentará de maneira não uniforme os IDs a cada vez.0xD5AA96...2373
(como uma chave secreta) e alguns bits serão invertidos. (sempre que a chave secreta estiver com 1 bit ativado, ela mudará a parte do ID). Isso tornará os IDs ainda mais difíceis de adivinhar e parecerá mais aleatórioSeguindo esse esquema, o servidor único que aloca os IDs pode formar os IDs, assim como os 20 ou 200 servidores que solicitam a alocação de IDs. O servidor de alocação precisa usar um bloqueio / semáforo para impedir que dois servidores solicitantes obtenham o mesmo lote (ou, se estiver aceitando uma conexão por vez, isso já resolve o problema). Portanto, não queremos que a linha (fila) seja muito longa para aguardar uma alocação. É por isso que alocar 1000 ou 10000 por vez pode resolver o problema.
fonte