Saya memiliki string seperti "Foo: Bar" yang ingin saya gunakan sebagai nama file, tetapi di Windows karakter ":" tidak diperbolehkan dalam nama file.
Apakah ada metode yang akan mengubah "Foo: Bar" menjadi seperti "Foo- Bar"?
Saya memiliki string seperti "Foo: Bar" yang ingin saya gunakan sebagai nama file, tetapi di Windows karakter ":" tidak diperbolehkan dalam nama file.
Apakah ada metode yang akan mengubah "Foo: Bar" menjadi seperti "Foo- Bar"?
Jawaban:
Coba sesuatu seperti ini:
string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
Edit:
Karena GetInvalidFileNameChars()
akan menghasilkan 10 atau 15 karakter, lebih baik menggunakan a StringBuilder
daripada string sederhana; versi aslinya akan membutuhkan waktu lebih lama dan menggunakan lebih banyak memori.
file.name.txt.pdf
adalah pdf yang valid. Windows hanya membaca yang terakhir .
untuk ekstensi.
fileName = fileName.Replace(":", "-")
Namun ":" bukan satu-satunya karakter ilegal untuk Windows. Anda juga harus menangani:
/, \, :, *, ?, ", <, > and |
Ini terkandung dalam System.IO.Path.GetInvalidFileNameChars ();
Juga (di Windows), "." tidak bisa menjadi satu-satunya karakter dalam nama file (baik ".", "..", "...", dan seterusnya tidak valid). Berhati-hatilah saat menamai file dengan ".", Misalnya:
echo "test" > .test.
Akan menghasilkan file bernama ".test"
Terakhir, jika Anda benar - benar ingin melakukan sesuatu dengan benar, ada beberapa nama file khusus yang perlu Anda perhatikan. Di Windows, Anda tidak dapat membuat file dengan nama:
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.
Ini tidak lebih efisien, tapi lebih menyenangkan :)
var fileName = "foo:bar";
var invalidChars = System.IO.Path.GetInvalidFileNameChars();
var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray<char>());
Jika ada yang menginginkan versi yang dioptimalkan berdasarkan StringBuilder
, gunakan ini. Termasuk trik rkagerer sebagai opsi.
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;
}
Berikut sedikit perubahan pada jawaban Diego.
Jika Anda tidak takut dengan Unicode, Anda dapat mempertahankan sedikit lebih banyak ketepatan dengan mengganti karakter yang tidak valid dengan simbol Unicode valid yang mirip dengan mereka. Inilah kode yang saya gunakan dalam proyek baru-baru ini yang melibatkan daftar potong kayu:
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;
}
Ini menghasilkan nama file seperti 1⁄2” spruce.txt
bukan1_2_ spruce.txt
Ya, ini benar-benar berfungsi:
Caveat Emptor
Saya tahu trik ini akan berfungsi pada NTFS tetapi saya terkejut menemukannya juga berfungsi pada partisi FAT dan FAT32. Itu karena nama file panjang yang disimpan dalam Unicode , bahkan sejauh sebagai Windows 95 / NT. Saya menguji pada Win7, XP, dan bahkan router berbasis Linux dan mereka muncul dengan baik. Tidak bisa mengatakan hal yang sama untuk di dalam DOSBox.
Karena itu, sebelum Anda menjadi gila dengan ini, pertimbangkan apakah Anda benar-benar membutuhkan kesetiaan ekstra. Mirip dengan Unicode dapat membingungkan orang atau program lama, misalnya OS lama yang mengandalkan halaman kode .
Berikut adalah versi jawaban yang diterima Linq
yang menggunakan Enumerable.Aggregate
:
string fileName = "something";
Path.GetInvalidFileNameChars()
.Aggregate(fileName, (current, c) => current.Replace(c, '_'));
Diego memang memiliki solusi yang tepat, tetapi ada satu kesalahan kecil di sana. Versi string.Replace yang digunakan harus string.Replace (char, char), tidak ada string. Ganti (char, string)
Saya tidak dapat mengedit jawabannya atau saya akan membuat perubahan kecil.
Jadi seharusnya:
string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
Berikut adalah versi yang menggunakan StringBuilder
dan IndexOfAny
dengan penambahan massal untuk efisiensi penuh. Ini juga mengembalikan string asli daripada membuat string duplikat.
Last but not least, ia memiliki pernyataan switch yang mengembalikan karakter yang mirip yang dapat Anda sesuaikan sesuka Anda. Lihat pencarian membingungkan Unicode.org untuk melihat opsi apa yang mungkin Anda miliki, tergantung pada fontnya.
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();
}
Ini tidak memeriksa .
, ..
atau nama-nama yang dicadangkan seperti CON
karena tidak jelas apa pengganti harus.
Membersihkan sedikit kode saya dan membuat sedikit refactoring ... Saya membuat ekstensi untuk tipe string:
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));
}
Sekarang lebih mudah digunakan dengan:
var name = "Any string you want using ? / \ or even +.zip";
var validFileName = name.ToValidFileName();
Jika Anda ingin mengganti dengan karakter yang berbeda dari "_", Anda dapat menggunakan:
var validFileName = name.ToValidFileName(replaceChar:'#');
Dan Anda dapat menambahkan karakter untuk diganti .. misalnya Anda tidak ingin spasi atau koma:
var validFileName = name.ToValidFileName(includeChars: new [] { ' ', ',' });
Semoga membantu ...
Bersulang
Solusi sederhana lainnya:
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());
}
Kode satu baris sederhana:
var validFileName = Path.GetInvalidFileNameChars().Aggregate(fileName, (f, c) => f.Replace(c, '_'));
Anda dapat membungkusnya dengan metode ekstensi jika Anda ingin menggunakannya kembali.
public static string ToValidFileName(this string fileName) => Path.GetInvalidFileNameChars().Aggregate(fileName, (f, c) => f.Replace(c, '_'));
Saya membutuhkan sistem yang tidak bisa membuat tabrakan jadi saya tidak bisa memetakan banyak karakter menjadi satu. Saya berakhir dengan:
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)));
}
}
Saya perlu melakukan ini hari ini ... dalam kasus saya, saya perlu menggabungkan nama pelanggan dengan tanggal dan waktu untuk file .kmz akhir. Solusi terakhir saya adalah ini:
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));
Anda bahkan dapat membuatnya mengganti spasi jika Anda menambahkan spasi char ke array yang tidak valid.
Mungkin ini bukan yang tercepat, tetapi karena kinerja bukanlah masalah, saya menganggapnya elegan dan dapat dimengerti.
Bersulang!
Anda dapat melakukan ini dengan sed
perintah:
sed -e "
s/[?()\[\]=+<>:;©®”,*|]/_/g
s/"$'\t'"/ /g
s/–/-/g
s/\"/_/g
s/[[:cntrl:]]/_/g"