ファイル名として使用したい「Foo:Bar」のような文字列がありますが、Windowsでは「:」文字をファイル名に使用できません。
「Foo:Bar」を「Foo-Bar」のようなものに変える方法はありますか?
次のようなことを試してください:
string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
編集:
GetInvalidFileNameChars()
は 10 文字または 15 文字を返すため、単純な文字列ではなく a を使用することStringBuilder
をお勧めします。元のバージョンは時間がかかり、より多くのメモリを消費します。
fileName = fileName.Replace(":", "-")
ただし、Windows で使用できない文字は ":" だけではありません。次のことも処理する必要があります。
/, \, :, *, ?, ", <, > and |
これらは System.IO.Path.GetInvalidFileNameChars(); に含まれています。
また (Windows の場合)、「.」ファイル名の唯一の文字にすることはできません (「.」、「..」、「...」などは無効です)。「.」を使用してファイルに名前を付けるときは注意してください。たとえば、次のようになります。
echo "test" > .test.
「.test」という名前のファイルを生成します
最後に、本当に正しく処理したい場合は、注意が必要な特別なファイル名がいくつかあります。Windows では、次の名前のファイルを作成できません。
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.
これは効率的ではありませんが、もっと楽しいです:)
var fileName = "foo:bar";
var invalidChars = System.IO.Path.GetInvalidFileNameChars();
var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray<char>());
Linq
which uses を使用した受け入れられた回答のバージョンは次のEnumerable.Aggregate
とおりです。
string fileName = "something";
Path.GetInvalidFileNameChars()
.Aggregate(fileName, (current, c) => current.Replace(c, '_'));
ディエゴは正しい解決策を持っていますが、そこには非常に小さな間違いが 1 つあります。使用されている string.Replace のバージョンは string.Replace(char, char) である必要があります。string.Replace(char, string) はありません。
回答を編集できないか、マイナーな変更を加えただけです。
したがって、次のようになります。
string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
StringBuilder
完全な効率のためにIndexOfAny
一括追加を使用するバージョンを次に示します。また、重複した文字列を作成するのではなく、元の文字列を返します。
最後に大事なことを言い忘れましたが、好きなようにカスタマイズできるそっくりな文字を返す switch ステートメントがあります。Unicode.org の confusables lookupを調べて、フォントに応じてどのようなオプションがあるかを確認してください。
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();
}
.
、..
、または のような予約済みの名前はチェックされませんCON
。これは、置き換えが明確でないためです。
sed
これは、次のコマンドで実行できます。
sed -e "
s/[?()\[\]=+<>:;©®”,*|]/_/g
s/"$'\t'"/ /g
s/–/-/g
s/\"/_/g
s/[[:cntrl:]]/_/g"