私のプログラムはインターネットから任意の文字列を取得し、それらをファイル名に使用します。これらの文字列から不良文字を削除する簡単な方法はありますか、またはこのためのカスタム関数を作成する必要がありますか?
回答:
ああ、私は人々がどの文字が有効であるかを推測しようとするときそれを嫌います。完全に移植性がない(常にMonoを考える)ことに加えて、以前のコメントはどちらも25文字以上の無効な文字を逃しました。
'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
無効な文字を取り除くには:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars
var validFilename = new string(filename.Where(ch => !invalidFileNameChars.Contains(ch)).ToArray());
無効な文字を置き換えるには:
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());
無効な文字を置き換えるには(そして、Hell *とHell $のような名前の競合を避けるため):
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());
この質問は以前に何 度 も尋ねられており、以前に何度も指摘されているように、適切ではありません。IO.Path.GetInvalidFileNameChars
1つ目は、PRNやCONなど、予約済みでファイル名に使用できない名前が多数あることです。ルートフォルダでのみ許可されていない他の名前があります。ピリオドで終わる名前も使用できません。
次に、さまざまな長さの制限があります。ここでNTFSの完全なリストを読んでください。
3番目に、他の制限があるファイルシステムにアタッチできます。たとえば、ISO 9660ファイル名は「-」で始めることはできませんが、含めることはできます。
4番目に、2つのプロセスが「任意に」同じ名前を選択した場合はどうしますか?
一般に、ファイル名に外部で生成された名前を使用することは悪い考えです。独自のプライベートファイル名を生成し、人間が読める名前を内部に保存することをお勧めします。
私はグラウエンウルフに同意し、強くお勧めします Path.GetInvalidFileNameChars()
ここに私のC#の貢献があります:
string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))";
Array.ForEach(Path.GetInvalidFileNameChars(),
c => file = file.Replace(c.ToString(), String.Empty));
ps-これは本来あるべきものよりも不可解です-私は簡潔にしようとしました。
Array.ForEach
だけforeach
ではなく、なぜ世界で使用するのですか
Path.GetInvalidFileNameChars().Aggregate(file, (current, c) => current.Replace(c, '-'))
これが私のバージョンです:
static string GetSafeFileName(string name, char replace = '_') {
char[] invalids = Path.GetInvalidFileNameChars();
return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray());
}
GetInvalidFileNameCharsの結果がどのように計算されるのかはわかりませんが、 "Get"はそれが重要であることを示唆しているため、結果をキャッシュします。さらに、これは無効な文字のセットを反復してソース文字列の文字を1つずつ置き換える上記のソリューションのように、複数回ではなく1回だけ入力文字列をトラバースします。また、私はWhereベースのソリューションが好きですが、無効な文字を削除するのではなく置き換えることを好みます。最後に、文字列を繰り返し処理するときに文字を文字列に変換することを避けるために、私の置換は正確に1文字です。
私はプロファイリングを行わないことをすべて言います-これは私にただ「感じた」だけです。:)
new HashSet<char>(Path.GetInvalidFileNameChars())
O(n)列挙を回避するために行うことができます-マイクロ最適化。
すべての特殊文字をすばやく削除したい場合は、ファイル名でユーザーが読みやすい場合がありますが、これはうまく機能します。
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
英数字以外([^A-Za-z0-9_]
)よりも多く一致します。すべてのUnicode「単語」文字(русский中文...など)も置き換えられません。しかし、これは良いことです。
.
ため、最初に拡張機能を抽出し、後で再度追加する必要があることです。
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);
}
}
文字列を次のように同等のBase64に変換してみませんか。
string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn";
string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName));
あなたがそれを読むことができるようにそれを元に戻したい場合:
UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName));
これを使用して、ランダムな説明から一意の名前でPNGファイルを保存しました。
上記のDour High Archが投稿した関連するStackoverflow質問へのリンクから収集した情報に基づいて、ClipFlair (http://github.com/Zoomicon/ClipFlair)のStringExtensions静的クラス(Utils.Silverlightプロジェクト)に追加した内容を次に示します。
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;
}
私の古いプロジェクトから、私はこのソリューションを見つけました。このソリューションは2年以上完全に機能しています。不正な文字を「!」に置き換えてから、二重の!!をチェックし、独自の文字を使用します。
public string GetSafeFilename(string filename)
{
string res = string.Join("!", filename.Split(Path.GetInvalidFileNameChars()));
while (res.IndexOf("!!") >= 0)
res = res.Replace("!!", "!");
return res;
}
多くのanwerはPath.GetInvalidFileNameChars()
私に悪い解決策のように思われる使用を提案しています。ハッカーは常に最終的にそれをバイパスする方法を見つけるため、ブラックリストではなくホワイトリストを使用することをお勧めします。
使用できるコードの例を次に示します。
string whitelist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
foreach (char c in filename)
{
if (!whitelist.Contains(c))
{
filename = filename.Replace(c, '-');
}
}