Récuperer un identifiant dans un nom de fichier avec une REGEXP

Fermé
AlBert38 - Modifié par Whismeril le 18/09/2015 à 14:18
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 - 19 sept. 2015 à 21:51
Bonjour,

j'écris un petit programme java qui va parcourir tout les fichiers d'un dossier pour en récupérer "l'identifiant" et renommé le fichier avec ce même identifiant.

ma lacune : les expressions régulières.

je cherche a détecter l'identifiant d'un numéro d'épisode de série TV à savoir une chaine de la forme "S**E**", les étoiles sont des caractères numériques.

Voici mon bout de code :
File dossier = new File("C:\\Users\\CHFN5382\\Downloads\\Nouveau dossier");

  if (dossier.isDirectory()) {

   // Pattern pattern = Pattern.compile("#^(.*)-S?([0-9]*)E([0-9]*)#i");
   Pattern pattern = Pattern.compile("S[0-9][0-9]E[0-9][0-9]");

   File[] files = dossier.listFiles();
   for (File file : files) {
    if (!file.isDirectory()) {
     String name = file.getName().toUpperCase();
     Matcher mattcher = pattern.matcher(name);
     if (mattcher.matches()) {
      String identifiant = mattcher.group(0);
      file.renameTo(new File(dossier.getPath() + "\\Ma série " + identifiant + ".avi"));
     }

    }
   }
  }


Pour mon test j'utilise ce fichier "NouS03e24veau document texte - Copie (3).txt", j'aimerai qu'il soit renommé en "Ma série S03E24.avi" pour le coup.

Si quelqu'un peut m'aider a faire une REGEXP qui fonctionne :)
Merci d'avance.

A voir également:

3 réponses

Nexii Messages postés 333 Date d'inscription jeudi 13 mars 2014 Statut Membre Dernière intervention 14 mars 2017 550
18 sept. 2015 à 11:20
[^S\-(.]*(S\d{2}[eE]\d{1,2}).*

Celle-ci semble fonctionner.

Amuse toi sur ce site : https://regexr.com/
0
Bonjour,

merci cela ne correspondait pas exactement a ce que je voulais mais je l'ai adapté :
([sS]\d{1,2}[eE]\d{1,2})

, je souhaite que seul le numéro de l'épisode match en fait, j'écrase le reste du nom de fichier

en tous cas merci pour le site il est génial !
0
Whismeril Messages postés 19030 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 avril 2024 931
18 sept. 2015 à 14:20
Bonjour, j'ai corrigé la coloration syntaxique dans ta question, voir ici comment bien l'utiliser.
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
18 sept. 2015 à 19:21
Bonjour,

Quelques remarques :

Pourquoi tester [sS] et [eE] alors que tu fais un toUpperCase qui te garantie d'avoir S et E et jamais s ou e ?
À l'inverse, si tu testes [sS] et [eE] et que ce qui t'intéresse ce sont juste des chiffres... tu n'as plus besoin du toUpperCase.

Avec \d{1,2} on se limite à 1 ou 2 chiffres par nombre, c'est peut-être suffisant mais c'est dommage de se limiter alors qu'un + permettrait d'avoir n'importe quel nombre.

Sans oublier ce qu'il peut y avoir avant ou après la partie qui matche que l'on peut simplement représenter par .*

Quant au groupe de capture il faut le placer au bon endroit, sachant que le groupe 0 correspond à toute la chaîne qui matche, et que les groupes spécifiques spécifiées par les parenthèses commencent à l'index 1.

Éventuellement on peut aussi s'arranger pour récupérer l'extension du fichier, ce qui évite de supposer que c'est effectivement un .avi alors que ça pourrait être autre chose.

Une bonne pratique maintenant : si tu as une boucle dont tout le corps est un if sans else (ce qui est ton cas), il est plus propre de prendre la condition inverse et d'utiliser un continue. On peut faire pareil pour une méthode et faire un return. Cela permet de limiter le nombre de niveaux d'imbrications

Enfin, par convention en Java, les chemins d'accès sont spécifiés avec / et pas \\ même pour Windows.

import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {

    private static final Pattern PATTERN = Pattern.compile(".*[sS]\\d+[eE](\\d+).*(\\.[^.]*)");

    public static void renameEpisodes(File directory, String renamePrefix) {

        if (!directory.isDirectory())
            return;

        for (File file : directory.listFiles()) {

            if (!file.isFile())
                continue;

            Matcher matcher = PATTERN.matcher(file.getName());

            if (!matcher.matches())
                continue;

            String num = matcher.group(1);
            String ext = matcher.group(2);

            file.renameTo(new File(directory, renamePrefix + num + ext));
        }
    }

    public static void main(String[] args) {
        renameEpisodes(new File("C:/Users/CHFN5382/Downloads/Nouveau dossier"), "Ma série ");
    }
}
0
Bonjour,

merci pour tes conseils, j'avais déjà commencer a refactorer mon code avec certain de tes conseil avant :) Mais je prend note de certain oubli en effet :)

voici la version avant ta réponse :
	public static void main(String[] args) {

		long start = System.currentTimeMillis();

		if (args.length == 0) {
			System.out.println(
					"USAGE : RenameSeriesFiles racineDuNomDeFichier [repertoire des fichier][-auto] \n -auto : repertoire courrant");
			return;
		}

		String racine = args[0];
		String root = args[1];

		if (root == "-auto") {
			root = ".\\";
		}
		System.out.println("root : " + root);
		System.out.println("serie : " + racine);

		renameProcess(root, racine);
		
		long end = System.currentTimeMillis();
		System.out.println("temps de traitement : " + (end - start) + "ms");
	}
	
	private static void renameProcess(String root, String prefixeNomFichier) {
		File dossier = new File(root);

		if (dossier.isDirectory()) {

			// Pattern pattern =
			// Pattern.compile("#^(.*)-S?([0-9]*)E([0-9]*)#i");
			Pattern pattern = Pattern.compile("S\\d\\dE\\d\\d");

			File[] files = dossier.listFiles();

			System.out.println("nombre de fichiers trouvés : " + files.length + "\n");
			int i = 0;
			int j = 0;
			for (File file : files) {
				if (!file.isDirectory()) {
					i++;
					String name = file.getName().toUpperCase();
					String extension = name.substring(name.lastIndexOf(".")).toLowerCase();
					//file.renameTo(new File(dossier.getPath() + "\\" + name.replaceAll(".S4E", ".S04E")));
					Matcher mattcher = pattern.matcher(name);
					if (mattcher.find()) {
						j++;
						String identifiant = mattcher.group(0);
						String newName = "\\" + prefixeNomFichier + " " + identifiant + extension;
						System.out.println(file.getName());
						System.out.println("rename >> " + newName + "\n");
						File newFile = new File(dossier.getPath() + newName);
						if (!fileExistInDirectory(dossier, newFile.getName())) {
							file.renameTo(new File(dossier.getPath() + newName));
						} else {
							System.err.println("un fichier porte déjà ce nom dans le dossier : " + newFile.getName());
						}
					} else {
						System.err.println(
								"l'identifiant de l'episode n'a pas été trouvé pour le fichier : " + file.getName());
					}
				}
			}

			System.out.println("nombre de fichiers : " + i);
			System.out.println("nombre de repertoires : " + (files.length - i));
			System.out.println("nombre de fichiers renomés : " + j);
		}
	}

	private static boolean fileExistInDirectory(File directory, String fileName) {
		boolean result = false;

		if (directory.isDirectory() && fileName != null) {
			for (File file : directory.listFiles()) {
				if (fileName.equals(file.getName())) {
					return true;
				}
			}
		} else {
			result = true;
		}
		return result;
	}
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015 > AlBert38
19 sept. 2015 à 15:53
Ce genre de code ne fonctionne pas :
if (root == "-auto")
parce que la comparaison avec == compare les objets pas leurs valeurs et qu'il est impossible que args[1] soit le même objet que "-auto" même s'ils ont la même valeur, de plus en récupérant args[1] tu supposes que args.length>=2 or la seule chose que tu testes c'est que si args.length!=0 ce qui est insuffisant.

public static void main(String[] args) {

    long start = System.currentTimeMillis();

    if (args.length < 2) {
        System.err.println("USAGE: RenameSeriesFiles racineDuNomDeFichier [repertoire des fichier][-auto]");
        System.err.println("    -auto : repertoire courant");
        return;
    }

    String racine = args[0];
    String root = args[1];

    if (root.equals("-auto"))
         root = ".\\"; // à tester: "" ou new File().getPath()

    ...

Pour la partie renommage des fichiers je te laisse regarder ma réponse d'hier.
0
AlBert38 > KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024
19 sept. 2015 à 20:39
oui je le sais en plus pour le .equals() c'est du code pas testé juste écris de manière compulsive en regardant des séries en même temps :)
j'avais dupliquer un ligne sur un test de lenght (donc du int primitif)

et pour le equals pour ma part je l'utilise plutot dans l'autre sens
"-auto".equals(root)
comme ca c'est null safe :D
0
AlBert38 > AlBert38
19 sept. 2015 à 20:41
avec une
private static final String AUTO = "-auto"
c'est encore plus joli :)
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
19 sept. 2015 à 21:51
Remarque :

Généralement on mets
x.equals(y)
lorsque c'est la variable
x
qui nous intéresse et que l'on regarde la valeur
y
. Dans ton cas il serait plus logique de mettre
root.equals(AUTO)


De toute façon args[1] ne peut pas être null... donc root non plus, du coup
AUTO.equals(root)
ou
root.equals(AUTO)
les deux ne posent aucun risque.

Et s'il y avait un risque d'avoir null, il serait mieux de tester explicitement la valeur avec un
if (x==null)
plutôt que déléguer ce contrôle à une méthode qui même si elle gère le cas peut faire plusieurs opérations avant de contrôler la valeur null.

Exemple, dans ton cas c'est la méthode equals de la classe String, voici son code :
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            ...
        }
        return false;
    }

Le cas où anObject est null est géré par instanceof qui renvoie false, mais la méthode a d'abord testé
this == anObject
au préalable, ce qui est inutile... on aurait tout simplement pu ne jamais appeler la méthode equals.
0