Programım internetten rastgele dizeler alacak ve bunları dosya isimleri için kullanacak. Bu dizelerden kötü karakterleri kaldırmanın basit bir yolu var mı yoksa bunun için özel bir işlev yazmam gerekiyor mu?
Programım internetten rastgele dizeler alacak ve bunları dosya isimleri için kullanacak. Bu dizelerden kötü karakterleri kaldırmanın basit bir yolu var mı yoksa bunun için özel bir işlev yazmam gerekiyor mu?
Yanıtlar:
Ugh, insanların hangi karakterlerin geçerli olduğunu tahmin etmesinden nefret ediyorum. Tamamen taşınabilir olmamasının yanı sıra (her zaman Mono'yu düşünür), önceki yorumların her ikisi de 25'ten fazla geçersiz karakteri kaçırdı.
'Clean just a filename
Dim filename As String = "salmnas dlajhdla kjha;dmas'lkasn"
For Each c In IO.Path.GetInvalidFileNameChars
filename = filename.Replace(c, "")
Next
'See also IO.Path.GetInvalidPathChars
Geçersiz karakterleri çıkarmak için:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars
var validFilename = new string(filename.Where(ch => !invalidFileNameChars.Contains(ch)).ToArray());
Geçersiz karakterleri değiştirmek için:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars and an _ for invalid ones
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? '_' : ch).ToArray());
Geçersiz karakterleri değiştirmek (ve Hell * - Hell $ gibi olası ad çakışmasını önlemek) için:
static readonly IList<char> invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars and replaces invalid chars with a unique letter (Moves the Char into the letter range of unicode, starting at "A")
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? Convert.ToChar(invalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray());
Bu soru sorulduğunda olmuştur birçok kez önce , önce defalarca belirttiği gibi, ve IO.Path.GetInvalidFileNameChars
yeterli değildir.
İlk olarak, PRN ve CON gibi ayrılmış ve dosya adlarına izin verilmeyen birçok ad vardır. Yalnızca kök klasörde izin verilmeyen başka adlar da vardır. Bir dönemle biten isimlere de izin verilmez.
İkincisi, çeşitli uzunluk sınırlamaları vardır. NTFS'nin tam listesini buradan okuyun .
Üçüncüsü, başka sınırlamaları olan dosya sistemlerine iliştirebilirsiniz. Örneğin, ISO 9660 dosya adları "-" ile başlayamaz ancak içerebilir.
Dördüncüsü, iki süreç "keyfi olarak" aynı adı seçerse ne yaparsınız?
Genel olarak, dosya adları için harici olarak oluşturulmuş adlar kullanmak kötü bir fikirdir. Kendi özel dosya adlarınızı oluşturmanızı ve insan tarafından okunabilir adları dahili olarak saklamanızı öneririm.
Grauenwolf'a katılıyorum ve kesinlikle tavsiye ederim Path.GetInvalidFileNameChars()
İşte benim C # katkım:
string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))";
Array.ForEach(Path.GetInvalidFileNameChars(),
c => file = file.Replace(c.ToString(), String.Empty));
ps - bu olması gerekenden daha şifreli - özlü olmaya çalışıyordum.
Array.ForEach
sadece yerine foreach
burada
Path.GetInvalidFileNameChars().Aggregate(file, (current, c) => current.Replace(c, '-'))
İşte benim versiyonum:
static string GetSafeFileName(string name, char replace = '_') {
char[] invalids = Path.GetInvalidFileNameChars();
return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray());
}
GetInvalidFileNameChars'ın sonucunun nasıl hesaplandığından emin değilim, ancak "Al" bunun önemsiz olmadığını gösteriyor, bu yüzden sonuçları önbelleğe alıyorum. Dahası, bu, giriş dizesini birden çok kez değil, yalnızca bir kez dolaşır, yukarıdaki çözümlerde olduğu gibi geçersiz karakterler kümesi üzerinde yinelenir ve bunları kaynak dizesinde birer birer değiştirir. Ayrıca, Nereye dayalı çözümleri seviyorum, ancak geçersiz karakterleri kaldırmak yerine değiştirmeyi tercih ediyorum. Son olarak, dizge üzerinde yinelediğimde karakterleri dizelere dönüştürmekten kaçınmak için değiştireceğim tam olarak bir karakterdir.
Tüm bunları profilleme yapmadan söylüyorum - bu sadece bana "iyi hissettirdi". :)
new HashSet<char>(Path.GetInvalidFileNameChars())
O (n) numaralandırmadan kaçınmak için yapabilirsiniz - mikro optimizasyon.
İşte şimdi kullandığım işlev (C # örneği için jcollum'a teşekkürler):
public static string MakeSafeFilename(string filename, char replaceChar)
{
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
filename = filename.Replace(c, replaceChar);
}
return filename;
}
Ben sadece kolaylık olması için bunu "Helpers" sınıfına koydum.
Dosya adları için bazen daha kullanıcı tarafından okunabilen tüm özel karakterleri hızlı bir şekilde çıkarmak istiyorsanız, bu iyi çalışır:
string myCrazyName = "q`w^e!r@t#y$u%i^o&p*a(s)d_f-g+h=j{k}l|z:x\"c<v>b?n[m]q\\w;e'r,t.y/u";
string safeName = Regex.Replace(
myCrazyName,
"\W", /*Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'*/
"",
RegexOptions.IgnoreCase);
// safeName == "qwertyuiopasd_fghjklzxcvbnmqwertyu"
\W
alfa sayısal olmayanlardan ( [^A-Za-z0-9_]
) daha fazlasıyla eşleşir . Tüm Unicode 'kelime' karakterleri de (русский 中文 ..., vb.) Değiştirilmeyecektir. Ama bu iyi bir şey.
.
nedenle önce uzantıyı çıkarmanız ve sonra tekrar eklemeniz gerekir.
static class Utils
{
public static string MakeFileSystemSafe(this string s)
{
return new string(s.Where(IsFileSystemSafe).ToArray());
}
public static bool IsFileSystemSafe(char c)
{
return !Path.GetInvalidFileNameChars().Contains(c);
}
}
Neden dizeyi aşağıdaki gibi Base64 eşdeğerine dönüştürmüyorsunuz:
string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn";
string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName));
Okuyabilmek için geri dönüştürmek istiyorsanız:
UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName));
Bunu, PNG dosyalarını rastgele bir açıklamadan benzersiz bir adla kaydetmek için kullandım.
İşte ClipFlair'in ( http://github.com/Zoomicon/ClipFlair ) StringExtensions statik sınıfına (Utils.Silverlight projesi), yukarıda Dour High Arch tarafından yayınlanan ilgili stackoverflow sorularına bağlantılardan toplanan bilgilere dayanarak ekledim:
public static string ReplaceInvalidFileNameChars(this string s, string replacement = "")
{
return Regex.Replace(s,
"[" + Regex.Escape(new String(System.IO.Path.GetInvalidPathChars())) + "]",
replacement, //can even use a replacement string of any length
RegexOptions.IgnoreCase);
//not using System.IO.Path.InvalidPathChars (deprecated insecure API)
}
private void textBoxFileName_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = CheckFileNameSafeCharacters(e);
}
/// <summary>
/// This is a good function for making sure that a user who is naming a file uses proper characters
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
internal static bool CheckFileNameSafeCharacters(System.Windows.Forms.KeyPressEventArgs e)
{
if (e.KeyChar.Equals(24) ||
e.KeyChar.Equals(3) ||
e.KeyChar.Equals(22) ||
e.KeyChar.Equals(26) ||
e.KeyChar.Equals(25))//Control-X, C, V, Z and Y
return false;
if (e.KeyChar.Equals('\b'))//backspace
return false;
char[] charArray = Path.GetInvalidFileNameChars();
if (charArray.Contains(e.KeyChar))
return true;//Stop the character from being entered into the control since it is non-numerical
else
return false;
}
Bunu hızlı ve anlaşılması kolay buluyorum:
<Extension()>
Public Function MakeSafeFileName(FileName As String) As String
Return FileName.Where(Function(x) Not IO.Path.GetInvalidFileNameChars.Contains(x)).ToArray
End Function
Bir nedeni çalışır string
olduğu IEnumerable
bir şekilde char
diziye ve orada string
bir sürer kurucu dizesi char
dizisi.
Eski projelerimden, 2 yıldır mükemmel çalışan bu çözümü buldum. Kuraldışı karakterleri "!" İle değiştiriyorum ve ardından çift !! 'i kontrol ediyorum, kendi karakterinizi kullanın.
public string GetSafeFilename(string filename)
{
string res = string.Join("!", filename.Split(Path.GetInvalidFileNameChars()));
while (res.IndexOf("!!") >= 0)
res = res.Replace("!!", "!");
return res;
}
Birçok cevap kullanmayı öneriyor Path.GetInvalidFileNameChars()
bana kötü bir çözüm gibi görünen . Kara listeye almak yerine beyaz listeyi kullanmanızı tavsiye ederim çünkü bilgisayar korsanları her zaman sonunda onu atlamanın bir yolunu bulacaktır.
İşte kullanabileceğiniz bir kod örneği:
string whitelist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
foreach (char c in filename)
{
if (!whitelist.Contains(c))
{
filename = filename.Replace(c, '-');
}
}