Dosya adı olarak kullanmak istediğim "Foo: Bar" gibi bir dizem var, ancak Windows'ta ":" karakterine dosya adında izin verilmiyor.
"Foo: Bar" ı "Foo-Bar" gibi bir şeye dönüştürecek bir yöntem var mı?
Dosya adı olarak kullanmak istediğim "Foo: Bar" gibi bir dizem var, ancak Windows'ta ":" karakterine dosya adında izin verilmiyor.
"Foo: Bar" ı "Foo-Bar" gibi bir şeye dönüştürecek bir yöntem var mı?
Yanıtlar:
Bunun gibi bir şey dene:
string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
Düzenle:
Yana GetInvalidFileNameChars()
10 veya 15 karakter döndürür, bir kullanmak daha iyidir StringBuilder
basit dize yerine; orijinal sürüm daha uzun sürer ve daha fazla bellek tüketir.
file.name.txt.pdf
geçerli bir pdf'dir. Windows .
, uzantı için yalnızca sonuncuyu okur .
fileName = fileName.Replace(":", "-")
Ancak ":", Windows için tek geçersiz karakter değildir. Ayrıca şunları da halletmeniz gerekecek:
/, \, :, *, ?, ", <, > and |
Bunlar System.IO.Path.GetInvalidFileNameChars ();
Ayrıca (Windows'ta) "." dosya adındaki tek karakter olamaz (".", "..", "..." ve diğerleri geçersizdir). Dosyaları "." İle adlandırırken dikkatli olun, örneğin:
echo "test" > .test.
".Test" adlı bir dosya oluşturur
Son olarak, işleri gerçekten doğru yapmak istiyorsanız, dikkat etmeniz gereken bazı özel dosya adları vardır . Windows'ta şu adla dosya oluşturamazsınız:
CON, PRN, AUX, CLOCK$, NUL
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
Bu daha verimli değil ama daha eğlenceli :)
var fileName = "foo:bar";
var invalidChars = System.IO.Path.GetInvalidFileNameChars();
var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray<char>());
Herhangi birinin optimize edilmiş bir sürüm istediği durumda StringBuilder
, bunu kullanın. Rkerer'in hilesini bir seçenek olarak içerir .
static char[] _invalids;
/// <summary>Replaces characters in <c>text</c> that are not allowed in
/// file names with the specified replacement character.</summary>
/// <param name="text">Text to make into a valid filename. The same string is returned if it is valid already.</param>
/// <param name="replacement">Replacement character, or null to simply remove bad characters.</param>
/// <param name="fancy">Whether to replace quotes and slashes with the non-ASCII characters ” and ⁄.</param>
/// <returns>A string that can be used as a filename. If the output string would otherwise be empty, returns "_".</returns>
public static string MakeValidFileName(string text, char? replacement = '_', bool fancy = true)
{
StringBuilder sb = new StringBuilder(text.Length);
var invalids = _invalids ?? (_invalids = Path.GetInvalidFileNameChars());
bool changed = false;
for (int i = 0; i < text.Length; i++) {
char c = text[i];
if (invalids.Contains(c)) {
changed = true;
var repl = replacement ?? '\0';
if (fancy) {
if (c == '"') repl = '”'; // U+201D right double quotation mark
else if (c == '\'') repl = '’'; // U+2019 right single quotation mark
else if (c == '/') repl = '⁄'; // U+2044 fraction slash
}
if (repl != '\0')
sb.Append(repl);
} else
sb.Append(c);
}
if (sb.Length == 0)
return "_";
return changed ? sb.ToString() : text;
}
Diego'nun cevabında ufak bir değişiklik var.
Unicode'dan korkmuyorsanız, geçersiz karakterleri onlara benzeyen geçerli Unicode sembolleriyle değiştirerek biraz daha aslına uygunluk sağlayabilirsiniz. Kereste kesme listelerini içeren yakın tarihli bir projede kullandığım kod:
static string MakeValidFilename(string text) {
text = text.Replace('\'', '’'); // U+2019 right single quotation mark
text = text.Replace('"', '”'); // U+201D right double quotation mark
text = text.Replace('/', '⁄'); // U+2044 fraction slash
foreach (char c in System.IO.Path.GetInvalidFileNameChars()) {
text = text.Replace(c, '_');
}
return text;
}
Bu, şu şekilde dosya adları üretir 1⁄2” spruce.txt
:1_2_ spruce.txt
Evet, gerçekten işe yarıyor:
Caveat Emptor
Bu numaranın NTFS üzerinde çalışacağını biliyordum ama FAT ve FAT32 bölümlerinde de çalıştığını görünce şaşırdım. Çünkü yıllardan bu uzun dosya adları olan Unicode depolanan bile, kadar geriye Windows 95 / NT olarak. Win7, XP ve hatta Linux tabanlı bir yönlendiricide test ettim ve iyi göründüler. Bir DOSBox için aynı şeyi söyleyemeyiz.
Bununla birlikte, bununla delirmeden önce, fazladan sadakate gerçekten ihtiyacınız olup olmadığını düşünün. Unicode benzerleri insanların veya eski programların kafasını karıştırabilir, örneğin eski işletim sistemlerinin kod sayfalarına güvenmesi gibi .
Aşağıda, aşağıdakileri Linq
kullanan kabul edilen cevabın bir versiyonu bulunmaktadır Enumerable.Aggregate
:
string fileName = "something";
Path.GetInvalidFileNameChars()
.Aggregate(fileName, (current, c) => current.Replace(c, '_'));
Diego'nun doğru çözümü var ama orada çok küçük bir hata var. Kullanılan string.Replace'in versiyonu string olmalıdır.Değiştir (char, char), string yok.Değiştir (char, string)
Cevabı düzenleyemem, yoksa küçük bir değişiklik yapardım.
Bu yüzden olmalı:
string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
İşte tam verimlilik için toplu ekleme kullanan StringBuilder
ve kullanan bir sürüm IndexOfAny
. Yinelenen bir dize oluşturmak yerine orijinal dizeyi de döndürür.
Son olarak, istediğiniz gibi özelleştirebileceğiniz benzer karakterleri döndüren bir switch deyimine sahiptir. Check out Unicode.org en confusables arama yazı tipine göre aklınıza gelebilecek seçeneklerin ne olduğunu görmek için.
public static string GetSafeFilename(string arbitraryString)
{
var invalidChars = System.IO.Path.GetInvalidFileNameChars();
var replaceIndex = arbitraryString.IndexOfAny(invalidChars, 0);
if (replaceIndex == -1) return arbitraryString;
var r = new StringBuilder();
var i = 0;
do
{
r.Append(arbitraryString, i, replaceIndex - i);
switch (arbitraryString[replaceIndex])
{
case '"':
r.Append("''");
break;
case '<':
r.Append('\u02c2'); // '˂' (modifier letter left arrowhead)
break;
case '>':
r.Append('\u02c3'); // '˃' (modifier letter right arrowhead)
break;
case '|':
r.Append('\u2223'); // '∣' (divides)
break;
case ':':
r.Append('-');
break;
case '*':
r.Append('\u2217'); // '∗' (asterisk operator)
break;
case '\\':
case '/':
r.Append('\u2044'); // '⁄' (fraction slash)
break;
case '\0':
case '\f':
case '?':
break;
case '\t':
case '\n':
case '\r':
case '\v':
r.Append(' ');
break;
default:
r.Append('_');
break;
}
i = replaceIndex + 1;
replaceIndex = arbitraryString.IndexOfAny(invalidChars, i);
} while (replaceIndex != -1);
r.Append(arbitraryString, i, arbitraryString.Length - i);
return r.ToString();
}
Adları kontrol etmez veya rezerve etmez .
, çünkü değiştirmenin ne olması gerektiği net değildir...
CON
Kodumu biraz temizliyor ve biraz yeniden düzenleme yapıyorum ... string türü için bir uzantı oluşturdum:
public static string ToValidFileName(this string s, char replaceChar = '_', char[] includeChars = null)
{
var invalid = Path.GetInvalidFileNameChars();
if (includeChars != null) invalid = invalid.Union(includeChars).ToArray();
return string.Join(string.Empty, s.ToCharArray().Select(o => o.In(invalid) ? replaceChar : o));
}
Şimdi aşağıdakilerle kullanmak daha kolay:
var name = "Any string you want using ? / \ or even +.zip";
var validFileName = name.ToValidFileName();
"_" Dışında farklı bir karakterle değiştirmek isterseniz şunları kullanabilirsiniz:
var validFileName = name.ToValidFileName(replaceChar:'#');
Ve değiştirmek için karakter ekleyebilirsiniz .. örneğin boşluk veya virgül istemezsiniz:
var validFileName = name.ToValidFileName(includeChars: new [] { ' ', ',' });
Umarım yardımcı olur...
Şerefe
Başka bir basit çözüm:
private string MakeValidFileName(string original, char replacementChar = '_')
{
var invalidChars = new HashSet<char>(Path.GetInvalidFileNameChars());
return new string(original.Select(c => invalidChars.Contains(c) ? replacementChar : c).ToArray());
}
Tek satırlık basit bir kod:
var validFileName = Path.GetInvalidFileNameChars().Aggregate(fileName, (f, c) => f.Replace(c, '_'));
Yeniden kullanmak istiyorsanız, bir uzatma yöntemine sarabilirsiniz.
public static string ToValidFileName(this string fileName) => Path.GetInvalidFileNameChars().Aggregate(fileName, (f, c) => f.Replace(c, '_'));
Çarpışma yaratamayan bir sisteme ihtiyacım vardı, bu yüzden birden fazla karakteri tek bir karaktere eşleyemedim. Şununla bitirdim:
public static class Extension
{
/// <summary>
/// Characters allowed in a file name. Note that curly braces don't show up here
/// becausee they are used for escaping invalid characters.
/// </summary>
private static readonly HashSet<char> CleanFileNameChars = new HashSet<char>
{
' ', '!', '#', '$', '%', '&', '\'', '(', ')', '+', ',', '-', '.',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '=', '@',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'[', ']', '^', '_', '`',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
};
/// <summary>
/// Creates a clean file name from one that may contain invalid characters in
/// a way that will not collide.
/// </summary>
/// <param name="dirtyFileName">
/// The file name that may contain invalid filename characters.
/// </param>
/// <returns>
/// A file name that does not contain invalid filename characters.
/// </returns>
/// <remarks>
/// <para>
/// Escapes invalid characters by converting their ASCII values to hexadecimal
/// and wrapping that value in curly braces. Curly braces are escaped by doubling
/// them, for example '{' => "{{".
/// </para>
/// <para>
/// Note that although NTFS allows unicode characters in file names, this
/// method does not.
/// </para>
/// </remarks>
public static string CleanFileName(this string dirtyFileName)
{
string EscapeHexString(char c) =>
"{" + (c > 255 ? $"{(uint)c:X4}" : $"{(uint)c:X2}") + "}";
return string.Join(string.Empty,
dirtyFileName.Select(
c =>
c == '{' ? "{{" :
c == '}' ? "}}" :
CleanFileNameChars.Contains(c) ? $"{c}" :
EscapeHexString(c)));
}
}
Bunu bugün yapmam gerekiyordu ... benim durumumda, son .kmz dosyası için bir müşteri adını tarih ve saatle birleştirmem gerekiyordu. Son çözümüm şuydu:
string name = "Whatever name with valid/invalid chars";
char[] invalid = System.IO.Path.GetInvalidFileNameChars();
string validFileName = string.Join(string.Empty,
string.Format("{0}.{1:G}.kmz", name, DateTime.Now)
.ToCharArray().Select(o => o.In(invalid) ? '_' : o));
Geçersiz diziye boşluk karakterini eklerseniz, boşlukların yerini bile alabilirsiniz.
Belki en hızlısı değil, ancak performans bir sorun olmadığı için zarif ve anlaşılır buldum.
Şerefe!
Bunu bir sed
komutla yapabilirsiniz:
sed -e "
s/[?()\[\]=+<>:;©®”,*|]/_/g
s/"$'\t'"/ /g
s/–/-/g
s/\"/_/g
s/[[:cntrl:]]/_/g"