Existe-t-il un moyen normalisé/librarié/testé dans .NET de prendre une chaîne arbitraire et de la modifier de manière à ce qu'elle représente un nom de fichier valide? Rouler ma propre fonction de remplacement de caractères est assez facile, mais j'aimerais un peu plus de robustesse et de résonance.Nettoyeur de nom de fichier sécurisé/autorisé pour .NET
Répondre
Ce problème n'est pas aussi simple que vous pouvez le penser. Non seulement les caractères dans Path.GetInvalidFileNameChars
sont illégaux, mais plusieurs noms de fichiers, tels que "PRN" et "CON", sont réservés par Windows et ne peuvent pas être créés. Tout nom qui se termine par "." est également illégal dans Windows. De plus, il existe différentes limites de longueur. Lire la liste complète here. Si cela ne suffit pas, différents systèmes de fichiers ont des limitations différentes, par exemple les noms de fichiers ISO 9660 ne peuvent pas commencer par "-" mais peuvent le contenir.
Avez-vous regardé Path.GetInvalidFileNameChars?
Ce plus une expression rationnelle est mon secours; Idéalement, j'aimerais quelque chose qui fait le remplacement aussi. –
Vous pouvez utiliser Path.GetInvalidFileNameChars pour vérifier quels caractères de la chaîne ne sont pas valides, et non les convertir en char valide comme un trait d'union, ou (si vous avez besoin de conversion bidirectionnelle) les remplacer par un jeton d'échappement tel que %
, suivi de la représentation hexadécimale de leurs codes Unicode (j'ai effectivement utilisé cette technique une fois mais je n'ai pas le code en main pour le moment).
EDIT: Juste au cas où quelqu'un serait intéressé, voici le code.
/// <summary>
/// Escapes an object name so that it is a valid filename.
/// </summary>
/// <param name="fileName">Original object name.</param>
/// <returns>Escaped name.</returns>
/// <remarks>
/// All characters that are not valid for a filename, plus "%" and ".", are converted into "%uuuu", where uuuu is the hexadecimal
/// unicode representation of the character.
/// </remarks>
private string EscapeFilename(string fileName)
{
char[] invalidChars=Path.GetInvalidFileNameChars();
// Replace "%", then replace all other characters, then replace "."
fileName=fileName.Replace("%", "%0025");
foreach(char invalidChar in invalidChars)
{
fileName=fileName.Replace(invalidChar.ToString(), string.Format("%{0,4:X}", Convert.ToInt16(invalidChar)).Replace(' ', '0'));
}
return fileName.Replace(".", "%002E");
}
/// <summary>
/// Unescapes an escaped file name so that the original object name is obtained.
/// </summary>
/// <param name="escapedName">Escaped object name (see the EscapeFilename method).</param>
/// <returns>Unescaped (original) object name.</returns>
public string UnescapeFilename(string escapedName)
{
//We need to temporarily replace %0025 with %! to prevent a name
//originally containing escaped sequences to be unescaped incorrectly
//(for example: ".%002E" once escaped is "%002E%0025002E".
//If we don't do this temporary replace, it would be unescaped to "..")
string unescapedName=escapedName.Replace("%0025", "%!");
Regex regex=new Regex("%(?<esc>[0-9A-Fa-f]{4})");
Match m=regex.Match(escapedName);
while(m.Success)
{
foreach(Capture cap in m.Groups["esc"].Captures)
unescapedName=unescapedName.Replace("%"+cap.Value, Convert.ToChar(int.Parse(cap.Value, NumberStyles.HexNumber)).ToString());
m=m.NextMatch();
}
return unescapedName.Replace("%!", "%");
}
Et -1 parce que ...? – Konamiman
Pouvez-vous fournir plus de détails sur ce que vous entendez par « générer à partir d'une chaîne arbitraire »? Sur la base de ce que vous dites, il semble que vous demandiez
Y at-il un moyen de prendre une chaîne arbitraire et de la modifier de façon à ce qu'elle représente un nom de fichier valide?
Si tel est le cas, alors il n'y a pas de fonction standard disponible à ma connaissance. Cependant, vous pouvez utiliser ce qui suit qui devrait faire l'affaire
public static string MakeValidFileName(string name) {
var invalid = Path.GetInvalidFileNameChars();
var builder = new StringBuilder();
foreach (var cur in name) {
builder.Append(invalid.Contains(cur) ? '_' : cur);
}
return builder.ToString();
}
Edité la question pour utiliser votre phrasé ... merci! –
Juste pour le plaisir, je l'ai fait dans une ligne ..
Regex.Replace("http://codereview.stackexchange.com/questions/33851/how-can-i-improve-my-code/33857#33857", "[" + string.Join("", Path.GetInvalidFileNameChars().Select (p => p.ToString())) + "]", "_")
Ceci est * exactement * pourquoi je ne voulais pas essayer de rouler le mien avec un simple remplacement regex. Merci. –