{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "aac555be-5d3b-4f3e-9e68-12abd6e029c3",
   "metadata": {},
   "source": [
    "# Trouver son Nom de Domaine court en .fr\n",
    "## Auteur: Jaxom\n",
    "## Licence: EUPL v1.3 ou suivantes\n",
    "\n",
    "\n",
    "Ce notebook permet de trouver des noms de domaine en .fr non-réservés, à partir de la liste des NDD réservés mis à disposition par l'AFNIC [1]. \n",
    "\n",
    "Son fonctionnement est basique :  \n",
    "1. générer l'ensemble des NDD possibles avec les caractères et la longueur souhaitée, \n",
    "2. faire une recherche dans la liste : si le NDD est absent, alors il est disponible !\n",
    "\n",
    "Le paramètrage du NND se fait sur les caractères possibles dans le générateur (chiffres, lettres, ASCII), mais aussi ceux requis dans le nom généré.\n",
    "\n",
    "\n",
    "[1]: https://www.afnic.fr/produits-services/services-associes/donnees-partagees/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "7d2d30b1-d6a6-4b22-87dc-142ecf19eba6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import itertools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "6a22d6d2-b118-4c85-9f09-7fc7733ca2f9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Nombre de NDD enregistrés :  10_119_222\n"
     ]
    }
   ],
   "source": [
    "FICHIER = '202607_OPENDATA_A-NomsDeDomaineEnPointFr.csv'\n",
    "donnees = pd.read_csv(FICHIER,sep=\";\",usecols=[0])\n",
    "print(\"Nombre de NDD enregistrés : \",f'{len(donnees):_}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "cbf59774-6e4e-4c4d-8c61-13df35a19487",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Nb NDD possibles en 2 lettres :  625\n",
      "Nb NDD possibles en 3 lettres :  7625\n",
      "Nb NDD possibles en 4 lettres :  230625\n"
     ]
    }
   ],
   "source": [
    "## Les caractères possibles dans le NDD :\n",
    "chars = \"abcdefghijklmnopqrstvvxyz\" #0123456789abcdefghijklmnopqrstuvwxyz\n",
    "voyelles=\"0123456789aeiouy\"\n",
    "\n",
    "## Les caractères souhaités dans le NDD (présence d'au moins 1 de la liste)\n",
    "#subs = [\"a\",\"e\",\"u\",\"i\",\"o\",\"y\"] #,\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"0\"]\n",
    "subs = [\"a\",\"e\",\"u\",\"i\",\"o\",\"y\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"0\"]\n",
    "#itertools.product(voyelles, repeat=1)\n",
    "\n",
    "deux_lettres = []\n",
    "trois_lettres = []\n",
    "quatre_lettres = []\n",
    "n = 4\n",
    "for i in range(1, n+1):\n",
    "    for item in itertools.product(chars, repeat=i):\n",
    "        if (len(item) == 2): #and any(y in item for y in subs) ):\n",
    "            deux_lettres.append(''.join(item)+\".fr\")\n",
    "        if (len(item) == 3 and any(y in item for y in subs) ):\n",
    "            trois_lettres.append(''.join(item)+\".fr\")\n",
    "        if (len(item) == 4 and any(y in item for y in subs) ):\n",
    "            quatre_lettres.append(''.join(item)+\".fr\")\n",
    "\n",
    "print(\"Nb NDD possibles en 2 lettres : \",len(deux_lettres))\n",
    "print(\"Nb NDD possibles en 3 lettres : \",len(trois_lettres))\n",
    "print(\"Nb NDD possibles en 4 lettres : \",len(quatre_lettres))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "9d929ca1-d788-4d17-b720-a6d38cee8e22",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1_527  domaines déjà réservés en 2 lettres.\n",
      "1963        aa.fr\n",
      "1964        àà.fr\n",
      "1965        ââ.fr\n",
      "1966        ää.fr\n",
      "1967        åå.fr\n",
      "            ...  \n",
      "10118132    95.fr\n",
      "10118254    96.fr\n",
      "10118402    97.fr\n",
      "10118726    98.fr\n",
      "10118923    99.fr\n",
      "Name: Nom de domaine, Length: 1527, dtype: object\n"
     ]
    }
   ],
   "source": [
    "## On extrait les domaines déjà réservés dans la liste\n",
    "## qui ont la taille souhaitée\n",
    "deux_lettres_existants = donnees[donnees[\"Nom de domaine\"].map(len) < 2 + 4]\n",
    "#df[df['amp'].map(len) == 495]\n",
    "print(f'{len(deux_lettres_existants):_}',\" domaines déjà réservés en 2 lettres.\")\n",
    "print(deux_lettres_existants[\"Nom de domaine\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "8d68f883-09e5-4de8-a11b-09ff6c3c3a6a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "28_676  domaines déjà réservés en 3 lettres.\n",
      "210         aaa.fr\n",
      "211         ààà.fr\n",
      "614         aab.fr\n",
      "901         aac.fr\n",
      "1360        aad.fr\n",
      "             ...  \n",
      "10119121    995.fr\n",
      "10119128    996.fr\n",
      "10119145    997.fr\n",
      "10119149    998.fr\n",
      "10119166    999.fr\n",
      "Name: Nom de domaine, Length: 28676, dtype: object\n"
     ]
    }
   ],
   "source": [
    "## On extrait les domaines déjà réservés dans la liste\n",
    "## qui ont la taille souhaitée\n",
    "trois_lettres_existants = donnees[donnees[\"Nom de domaine\"].map(len) < 3 + 4]\n",
    "#df[df['amp'].map(len) == 495]\n",
    "print(f'{len(trois_lettres_existants):_}',\" domaines déjà réservés en 3 lettres.\")\n",
    "print(trois_lettres_existants[\"Nom de domaine\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc341547-ba4c-4207-9638-ef6d899dedf6",
   "metadata": {},
   "source": [
    "## Comparaison générés - réservés"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "bb2487b1-9751-4a03-9918-ccf8d24d6c5d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "14  domaines non réservés :\n",
      "['bl.fr', 'co.fr', 'fr.fr', 'gf.fr', 'gp.fr', 'mf.fr', 'mq.fr', 'nc.fr', 'pf.fr', 'pm.fr', 're.fr', 'tf.fr', 'tm.fr', 'yt.fr']\n"
     ]
    }
   ],
   "source": [
    "libres = []\n",
    "for ndd in deux_lettres:\n",
    "    if (ndd not in deux_lettres_existants[\"Nom de domaine\"].values.tolist()):\n",
    "        libres.append(ndd)\n",
    "print(len(libres), \" domaines non réservés :\")\n",
    "print(libres)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "a3e93119-0ef7-4223-8463-b4d852badeaa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "264  domaines non réservés :\n",
      "['aqv.fr', 'aqv.fr', 'com.fr', 'cqy.fr', 'dqy.fr', 'ejq.fr', 'ekq.fr', 'eqd.fr', 'eqj.fr', 'eyj.fr', 'eyq.fr', 'eyx.fr', 'ezq.fr', 'fqa.fr', 'fqo.fr', 'fqy.fr', 'fyq.fr', 'gjy.fr', 'gqo.fr', 'gqy.fr', 'gyq.fr', 'gzy.fr', 'heq.fr', 'hxi.fr', 'ihq.fr', 'ikq.fr', 'ilq.fr', 'iqb.fr', 'iqj.fr', 'iqk.fr', 'iqy.fr', 'ivq.fr', 'ivq.fr', 'ixb.fr', 'ixf.fr', 'ixh.fr', 'ixj.fr', 'ixq.fr', 'ixv.fr', 'ixv.fr', 'ixz.fr', 'iyb.fr', 'iym.fr', 'izg.fr', 'izj.fr', 'izq.fr', 'jqe.fr', 'jqi.fr', 'jqo.fr', 'jqy.fr', 'jxe.fr', 'jxy.fr', 'jyq.fr', 'kqa.fr', 'kqe.fr', 'kqo.fr', 'kqy.fr', 'kyq.fr', 'lqo.fr', 'lzy.fr', 'mhy.fr', 'nom.fr', 'nqo.fr', 'nyq.fr', 'oeq.fr', 'ogq.fr', 'ojx.fr', 'ojz.fr', 'oqb.fr', 'oqd.fr', 'oqj.fr', 'oqm.fr', 'oqx.fr', 'otq.fr', 'oxh.fr', 'oxj.fr', 'oxq.fr', 'oyf.fr', 'oyh.fr', 'oyj.fr', 'oyq.fr', 'oyv.fr', 'oyv.fr', 'ozj.fr', 'pjy.fr', 'pqy.fr', 'qby.fr', 'qeh.fr', 'qek.fr', 'qfo.fr', 'qfy.fr', 'qgi.fr', 'qgy.fr', 'qha.fr', 'qhe.fr', 'qhy.fr', 'qic.fr', 'qig.fr', 'qje.fr', 'qji.fr', 'qke.fr', 'qki.fr', 'qky.fr', 'qly.fr', 'qny.fr', 'qoj.fr', 'qqe.fr', 'qqi.fr', 'qqy.fr', 'qxa.fr', 'qxe.fr', 'qxi.fr', 'qyb.fr', 'qyc.fr', 'qye.fr', 'qyg.fr', 'qyh.fr', 'qyi.fr', 'qyj.fr', 'qyk.fr', 'qyl.fr', 'qym.fr', 'qyv.fr', 'qyv.fr', 'qyx.fr', 'qyz.fr', 'qzo.fr', 'rgy.fr', 'rqi.fr', 'rqo.fr', 'rxy.fr', 'syj.fr', 'tjy.fr', 'tpy.fr', 'tqo.fr', 'tqy.fr', 'tyj.fr', 'tyq.fr', 'vjo.fr', 'vjy.fr', 'vmy.fr', 'vqi.fr', 'vqy.fr', 'vxe.fr', 'vyy.fr', 'vjo.fr', 'vjy.fr', 'vmy.fr', 'vqi.fr', 'vqy.fr', 'vxe.fr', 'vyy.fr', 'xcy.fr', 'xgy.fr', 'xhy.fr', 'xij.fr', 'xiy.fr', 'xja.fr', 'xje.fr', 'xke.fr', 'xny.fr', 'xoj.fr', 'xqa.fr', 'xqe.fr', 'xqi.fr', 'xqo.fr', 'xqy.fr', 'xsy.fr', 'xvy.fr', 'xvy.fr', 'xyf.fr', 'xyj.fr', 'ybq.fr', 'ycq.fr', 'ycx.fr', 'ydq.fr', 'ydt.fr', 'yeq.fr', 'yfh.fr', 'ygj.fr', 'ygq.fr', 'yhf.fr', 'yhq.fr', 'yhx.fr', 'yiq.fr', 'yjf.fr', 'yjn.fr', 'yjq.fr', 'yjx.fr', 'ykq.fr', 'ylq.fr', 'ynq.fr', 'ypj.fr', 'ypq.fr', 'yqc.fr', 'yqd.fr', 'yqf.fr', 'yqg.fr', 'yqi.fr', 'yqj.fr', 'yqk.fr', 'yql.fr', 'yqm.fr', 'yqn.fr', 'yqs.fr', 'yqt.fr', 'yqv.fr', 'yqv.fr', 'yqx.fr', 'yqy.fr', 'yqz.fr', 'yrq.fr', 'ytq.fr', 'ytx.fr', 'yvj.fr', 'yvm.fr', 'yvq.fr', 'yvx.fr', 'yvj.fr', 'yvm.fr', 'yvq.fr', 'yvx.fr', 'yxb.fr', 'yxd.fr', 'yxf.fr', 'yxh.fr', 'yxi.fr', 'yxk.fr', 'yxn.fr', 'yxp.fr', 'yxq.fr', 'yxr.fr', 'yxt.fr', 'yxv.fr', 'yxv.fr', 'yzg.fr', 'yzh.fr', 'yzj.fr', 'yzk.fr', 'yzm.fr', 'yzn.fr', 'yzq.fr', 'yzv.fr', 'yzv.fr', 'zcy.fr', 'zge.fr', 'zgi.fr', 'zij.fr', 'zje.fr', 'zji.fr', 'zjo.fr', 'zjy.fr', 'zoj.fr', 'zqe.fr', 'zqo.fr', 'zqy.fr', 'zsy.fr', 'zvy.fr', 'zvy.fr', 'zyd.fr', 'zyh.fr', 'zyj.fr', 'zyv.fr', 'zyv.fr']\n"
     ]
    }
   ],
   "source": [
    "libres = []\n",
    "for ndd in trois_lettres:\n",
    "    if (ndd not in trois_lettres_existants[\"Nom de domaine\"].values.tolist()):\n",
    "        libres.append(ndd)\n",
    " \n",
    "print(f'{len(libres):_}', \" domaines non réservés :\")\n",
    "print(libres)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8f85252-9282-4526-a537-da8ff36a40d3",
   "metadata": {},
   "source": [
    "## Idées d'amélioration\n",
    "Pour trouver des candidats \"lisibles\", on pourrait:\n",
    "* partir d'un dictionnaire FR existant\n",
    "* faire des substitutions en l33tsp34k"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
