Regex Remplacement

fury-fatal
Invité n'ayant pas de compte PHPfrance

27 mai 2019, 19:13

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Ajouter des URLs</title>
</head>
<body>
    
    <form method="post">
        <fieldset>
            <legend>Ajouter des URLs</legend>
                <label for="url">URLs : <input type="text" name="url" id="url" placeholder="*.exemple.com/*" ></label><br>

                <?php
                if ($_SERVER["REQUEST_METHOD"] == "POST")
                {
                    $url2 = null;
                    $url2 = $_POST["url"];
                    $url2 = preg_replace('#https://www.|http://www.|https://|http://#', '*.', $url2); // Remplacement
                    

                    $search = "//*$/";
                    if (!preg_match($search, $url2)) {
                        $url2 = $url2.'/*'; // Ajoute /* à la fin s'il n'y a pas encore
                    }
       

                    echo '<label for="url2">URL : <input type="text" value="'.$url2.'" name="url2" id="url2"></label>';
                }
                ?>
                <button type="submit">Ajouter</button>
        </fieldset>
    </form>

    <p>A tester :<br>
    https://www.exemple.fr<br>
    http://www.exemple.fr<br>
    https://exemple.fr<br>
    http://exemple.fr<br>
    www.exemple.fr<br>
    exemple.fr<br><br>
    Le résultat doit être : *.exemple.fr/*    
    </p>
</body>
</html>
Bonjour, je cherche à remplacer :
https://www.
http://www.
https://
http://
www

par *.

Mais j'arrive que pour les 4 premiers exemples.
Et pour ajouter /* tout à la fin, j'ai ce message d'erreur : Warning: preg_match(): Unknown modifier '*' in D:\Programmes\Developpement\Xampp\htdocs\regex\index.php on line 24

Merci d'avance

Avatar du membre
Mammouth du PHP | 1609 Messages

27 mai 2019, 19:24

Salut, pas sur de l'avoir bien écrit dans le php mais ça fonctionne ici https://regexr.com/4ep41
preg_replace('`((http(s|):\/\/)|)(www\.|)(\w+\.\w+)`', '*.$5/*', $url);
Développeur web depuis + de 20 ans

fury-fatal
Invité n'ayant pas de compte PHPfrance

27 mai 2019, 21:25

Merci, juste un truc qui ne va pas. Si je tape directement *.exemple.fr/*, il va me rajouter *. devant et /* derrière.

Et aussi je ne comprends pas pourquoi il faut mettre des guillemets supplémentaires ``.

Avatar du membre
Mammouth du PHP | 1609 Messages

27 mai 2019, 21:39

Les ` c'est le délimiteur du pattern comme les # dans ton expression originale, on utilise souvent les /. J'utilise l'accent grave car c'est rare d'en avoir besoin dans le pattern en lui même et que si tu utilises le délimiteur dans le pattern tu dois alors l'échapper (d'ailleurs je suis en train de me dire que t'es peut être pas obligé d'échapper les / du coup ^^). Et puis que j'aime bien me différencier, je suis un vrai rebelle. :mrgreen:

preg_replace('`(\*\.|)((http(s|):\/\/)|)(www\.|)(\w+\.\w+)(\/\*|)`', '*.$6/*', $url)

Est ce que celle la fonctionne ? :oops: ça ne provoque pas d'erreur sur regexr.com mais y a quand même une alerte (pourrait causer un problème lors du copié collé de l'expression dans du code) mais vu que le délimiteur est le `et non le slash ça serait supposé fonctionner.
preg_replace('`(\*\.|)((http(s|)://)|)(www\.|)(\w+\.\w+)(/\*|)`', '*.$6/*', $url)
Développeur web depuis + de 20 ans

fury-fatal
Invité n'ayant pas de compte PHPfrance

27 mai 2019, 22:24

Merci ça marche bien !

Mais je n'arrive pas à comprendre le nombre avec le dollar : $5 ou $6.
Et aussi le séparateur d'expression : |

Avatar du membre
Mammouth du PHP | 1609 Messages

27 mai 2019, 22:43

Les $n ça correspond aux groupes capturés par les parenthèses (). Chaque paire de parenthèses capturent une partie de l'expression. Dans la première expression que je t'ai proposé, c'était la cinquième paire de parenthèses (le cinquième groupe) qui capturait le exemple.fr d'où l'utilisation du $5 dans l'expression de remplacement. Dans la deuxième expression que je t'ai proposé, comme j'ai rajouté un groupe au début de l'expression, le groupe capturant exemple.fr devient donc le 6ème groupe soit $6. $0 doit être l'expression complète.

Les | représente un OU. Par exemple /http(s|)/ capturera https ou http.
Développeur web depuis + de 20 ans

Petit nouveau ! | 7 Messages

29 mai 2019, 19:16

J'ai testé de nouveaux cas. Certains ne fonctionnent pas. J'ai modifié un peu pour que ça marche : https://regexr.com/4eu7n

Code : Tout sélectionner

$url2 = preg_replace('`(\*|)(\.|)(http(s|):\/\/|)(www.|)(\w+.\w+)(\/|)(\*|)`', '*.$6/*', $url2);
Mais cela ne marche pas s'il y a un sous-domaine.

Voici la liste totale à vérifier :

https://www.exemple.fr
http://www.exemple.fr
https://www.exemple.fr/
http://www.exemple.fr/
https://exemple.fr
http://exemple.fr
https://exemple.fr/
http://exemple.fr/
www.exemple.fr
www.exemple.fr/
exemple.fr
exemple.fr/
*exemple.fr
*exemple.fr/
.exemple.fr
.exemple.fr/
*.exemple.fr/*
sousdomaine.exemple.fr
http://sousdomaine.exemple.fr

Résultats attendus :
*.exemple.fr/*
ou *.sousdomaine.exemple.fr/*

Avatar du membre
Mammouth du PHP | 1609 Messages

29 mai 2019, 20:19

Peut être pas la façon la plus simple de l'écrire mais ça fonctionne (et le replacement c'est *.$5/*) :
'`((http(s|):\/\/)|)(www\.|\*\.|\*|\.|)([a-z0-9-]+\.[a-z0-9-]+(\.[a-z0-9-]+|))(\/|)(\*|)`'
Je me suis rendu compte qu'il vaut mieux utiliser [a-z0-9-] à la place de \w (\w n'accepte pas les tirets) pour supporter les noms de domaine type :
sous-domaine.nom-de-domaine.fr
Développeur web depuis + de 20 ans

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 9782 Messages

29 mai 2019, 22:07

J'ai fait une regex assez complète pour gérer à ma connaissance tous les cas particuliers qu'on peut trouver dans les noms de domaines.

Voici le résultat :

Code : Tout sélectionner

^((http(s|):\/\/)|)((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+(xn--)?[a-z0-9-]{1,62}[a-z]$

Sur un jeu de test de 1546 noms de domaine valides et 9 cas particuliers invalides, ça donne ça :
https://regex101.com/r/GrNQlE/1


Et ça permet aussi de tester d'autres regex pour voir si elles donnent un meilleur résultat :-D


Cette regex est uniquement pour les noms de domaines donc à légèrement adapter si tu veux pouvoir ajouter un slash / à la fin ou une étoile * au début...
Quand tout le reste a échoué, lisez le mode d'emploi...

Petit nouveau ! | 7 Messages

29 mai 2019, 22:47

Peut être pas la façon la plus simple de l'écrire mais ça fonctionne (et le replacement c'est *.$5/*) :
'`((http(s|):\/\/)|)(www\.|\*\.|\*|\.|)([a-z0-9-]+\.[a-z0-9-]+(\.[a-z0-9]+|))(\/|)(\*|)`'
Je me suis rendu compte qu'il vaut mieux utiliser [a-z0-9-] à la place de \w (\w n'accepte pas les tirets) pour supporter les noms de domaine type :
sous-domaine.nom-de-domaine.fr
Merci. Mais pourquoi les doubles parenthèses autour de http ? Il n'y a pas un \*\.| en trop ?
Si j'enlève les doubles parenthèses, ca marche aussi : https://regexr.com/4eui7
'`(\*|)(\.|)(http(s|):\/\/|)(www\.|\*\.|)([a-z0-9-_]+\.[a-z0-9-_]+(\.\w+|))(\/|)(\*|)`'

J'ai fait une regex assez complète pour gérer à ma connaissance tous les cas particuliers qu'on peut trouver dans les noms de domaines.

Voici le résultat :

Code : Tout sélectionner

^((http(s|):\/\/)|)((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+(xn--)?[a-z0-9-]{1,62}[a-z]$

Sur un jeu de test de 1546 noms de domaine valides et 9 cas particuliers invalides, ça donne ça :
https://regex101.com/r/GrNQlE/1


Et ça permet aussi de tester d'autres regex pour voir si elles donnent un meilleur résultat :-D


Cette regex est uniquement pour les noms de domaines donc à légèrement adapter si tu veux pouvoir ajouter un slash / à la fin ou une étoile * au début...
Si je fais ça, ça me retire l'extension :

Code : Tout sélectionner

(\*|)(\.|)((http(s|):\/\/)|)((?=[a-z0-9-_]{1,63}\.)(xn--)?[a-z0-9-_]+(-[a-z0-9-_]+)*\.)+(xn--)?[a-z0-9-_]{1,62}[a-z](\/|)(\*|)
Test : https://regex101.com/r/GrNQlE/2
Remplacement : *.$6/*

Avatar du membre
Mammouth du PHP | 1609 Messages

29 mai 2019, 23:48

Comme je disais c'est peut être pas la plus simple. :mrgreen:
Effectivement y a des parenthèses facultatives autour du https:// ça fonctionne très bien sans.
Le \*\. dans (www\.|\*\.|\*|\.|) sert pour la variante *.exemple.fr/* qui fait un **.exemple.fr/* sans mais ça pourrait surement s'écrire différemment.
En tout cas l'expression '`(http(s|):\/\/|)(www\.|\*\.|\*|\.|)([a-z0-9-]+\.[a-z0-9-]+(\.[a-z0-9-]+|))(\/|)(\*|)`' fonctionne bien sur toute cette liste d'adresses :

sous-domaine.nom-de-domaine.fr
.exemple-de-domaine.fr
.exemple.fr
.exemple.fr/
*.exemple.fr/*
sousdomaine.exemple.fr
http://sousdomaine.exemple.fr
https://www.exemple.fr
http://www.exemple.fr
https://www.exemple.fr/
http://www.exemple.fr/
https://exemple.fr
http://exemple.fr
https://exemple.fr/
http://exemple.fr/
www.exemple.fr
www.exemple.fr/
exemple.fr
exemple.fr/
*exemple.fr
*exemple.fr/

*.$4/*

*.sous-domaine.nom-de-domaine.fr/*
*.exemple-de-domaine.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.sousdomaine.exemple.fr/*
*.sousdomaine.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
*.exemple.fr/*
Développeur web depuis + de 20 ans

Petit nouveau ! | 7 Messages

30 mai 2019, 12:51

Merci, en simplifiant, j'obtiens ça et ça marche :

Code : Tout sélectionner

(\*|)(\.|)(http(s|):\/\/|)(www.|)([a-z0-9-_]+.[a-z0-9-_]+.\w+)(\/|)(\*|)
*.$6/*

Testé avec tous les exemples : https://regexr.com/4evf3