アプリケーションにバッチファイルの名前変更機能を含めたい。ユーザーは宛先ファイル名パターンを入力できます。(パターン内のいくつかのワイルドカードを置き換えた後)Windowsで有効なファイル名になるかどうかを確認する必要があります。のような正規表現を使用しようとしました[a-zA-Z0-9_]+
が、さまざまな言語(ウムラウトなど)の各国固有の文字が多く含まれていません。そのようなチェックを行うための最良の方法は何ですか?
27 に答える
MSDN の「ファイルまたはディレクトリの名前付け」から、Windows での有効なファイル名の一般的な規則を次に示します。
現在のコード ページ (127 を超える Unicode/ANSI) の任意の文字を使用できます。
<
>
:
"
/
\
|
?
*
- 整数表現が 0 ~ 31 の文字 (ASCII スペース未満)
- ターゲット ファイル システムで許可されていないその他の文字 (末尾のピリオドやスペースなど)
- DOS 名のいずれか: CON、PRN、AUX、NUL、COM0、COM1、COM2、COM3、COM4、COM5、COM6、COM7、COM8、COM9、LPT0、LPT1、LPT2、LPT3、LPT4、LPT5、LPT6、LPT7、 LPT8、LPT9 (AUX.txt などは避ける)
- ファイル名はすべてピリオドです
チェックするいくつかのオプションの事柄:
- ファイル パス (ファイル名を含む) は 260 文字を超えることはできません (
\?\
プレフィックスを使用しない場合) 。 - 使用時に 32,000 文字を超える Unicode ファイル パス (ファイル名を含む)
\?\
(プレフィックスによってディレクトリ コンポーネントが拡張され、32,000 の制限を超える可能性があることに注意してください)
Path.GetInvalidPathChars
およびから無効な文字のリストを取得できますGetInvalidFileNameChars
。
UPD:これらを正規表現で使用する方法については、Steve Cooper の提案を参照してください。
UPD2: MSDN の備考セクションによると、「このメソッドから返された配列には、ファイル名とディレクトリ名で無効な文字の完全なセットが含まれているとは限りません。」sixlettervaliables によって提供された回答は、より詳細になります。
3.5 より前の .Net Framework の場合、これは機能するはずです。
正規表現の一致は、ある程度の方法で取得する必要があります。System.IO.Path.InvalidPathChars
定数を使用したスニペットを次に示します。
bool IsValidFilename(string testName)
{
Regex containsABadCharacter = new Regex("["
+ Regex.Escape(System.IO.Path.InvalidPathChars) + "]");
if (containsABadCharacter.IsMatch(testName)) { return false; };
// other checks for UNC, drive-path format, etc
return true;
}
3.0 以降の .Net Frameworkの場合、これは機能するはずです。
http://msdn.microsoft.com/en-us/library/system.io.path.getinvalidpathchars(v=vs.90).aspx
正規表現の一致は、ある程度の方法で取得する必要があります。System.IO.Path.GetInvalidPathChars()
定数を使用したスニペットを次に示します。
bool IsValidFilename(string testName)
{
Regex containsABadCharacter = new Regex("["
+ Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]");
if (containsABadCharacter.IsMatch(testName)) { return false; };
// other checks for UNC, drive-path format, etc
return true;
}
それがわかったら、さまざまな形式も確認する必要がありますc:\my\drive
。\\server\share\dir\file.ext
それを使用してみて、エラーをトラップしてください。許可されたセットは、ファイル システム間、または Windows の異なるバージョン間で変更される場合があります。つまり、Windows がその名前を気に入っているかどうかを知りたい場合は、名前を渡して教えてもらいます。
このクラスはファイル名とパスをクリーンアップします。次のように使用します
var myCleanPath = PathSanitizer.SanitizeFilename(myBadPath, ' ');
これがコードです。
/// <summary>
/// Cleans paths of invalid characters.
/// </summary>
public static class PathSanitizer
{
/// <summary>
/// The set of invalid filename characters, kept sorted for fast binary search
/// </summary>
private readonly static char[] invalidFilenameChars;
/// <summary>
/// The set of invalid path characters, kept sorted for fast binary search
/// </summary>
private readonly static char[] invalidPathChars;
static PathSanitizer()
{
// set up the two arrays -- sorted once for speed.
invalidFilenameChars = System.IO.Path.GetInvalidFileNameChars();
invalidPathChars = System.IO.Path.GetInvalidPathChars();
Array.Sort(invalidFilenameChars);
Array.Sort(invalidPathChars);
}
/// <summary>
/// Cleans a filename of invalid characters
/// </summary>
/// <param name="input">the string to clean</param>
/// <param name="errorChar">the character which replaces bad characters</param>
/// <returns></returns>
public static string SanitizeFilename(string input, char errorChar)
{
return Sanitize(input, invalidFilenameChars, errorChar);
}
/// <summary>
/// Cleans a path of invalid characters
/// </summary>
/// <param name="input">the string to clean</param>
/// <param name="errorChar">the character which replaces bad characters</param>
/// <returns></returns>
public static string SanitizePath(string input, char errorChar)
{
return Sanitize(input, invalidPathChars, errorChar);
}
/// <summary>
/// Cleans a string of invalid characters.
/// </summary>
/// <param name="input"></param>
/// <param name="invalidChars"></param>
/// <param name="errorChar"></param>
/// <returns></returns>
private static string Sanitize(string input, char[] invalidChars, char errorChar)
{
// null always sanitizes to null
if (input == null) { return null; }
StringBuilder result = new StringBuilder();
foreach (var characterToTest in input)
{
// we binary search for the character in the invalid set. This should be lightning fast.
if (Array.BinarySearch(invalidChars, characterToTest) >= 0)
{
// we found the character in the array of
result.Append(errorChar);
}
else
{
// the character was not found in invalid, so it is valid.
result.Append(characterToTest);
}
}
// we're done.
return result.ToString();
}
}
これは私が使用するものです:
public static bool IsValidFileName(this string expression, bool platformIndependent)
{
string sPattern = @"^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+$";
if (platformIndependent)
{
sPattern = @"^(([a-zA-Z]:|\\)\\)?(((\.)|(\.\.)|([^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?))\\)*[^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?$";
}
return (Regex.IsMatch(expression, sPattern, RegexOptions.CultureInvariant));
}
最初のパターンは、Windows プラットフォーム専用の無効/違法なファイル名と文字を含む正規表現を作成します。2 番目のものは同じことを行いますが、その名前がどのプラットフォームでも有効であることを保証します。
最初に知ったときは驚きました: Windows では、ファイル名の先頭に空白文字を使用できます。たとえば、以下はすべて、Windows での正当で個別のファイル名です (引用符を除く)。
"file.txt"
" file.txt"
" file.txt"
ここからの 1 つのポイント: ファイル名の文字列から先頭/末尾の空白を削除するコードを記述するときは注意してください。
Eugene Katzの答えを単純化する:
bool IsFileNameCorrect(string fileName){
return !fileName.Any(f=>Path.GetInvalidFileNameChars().Contains(f))
}
または
bool IsFileNameCorrect(string fileName){
return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
Microsoft Windows: Windows カーネルでは、1 ~ 31 の範囲の文字 (つまり、0x01 ~ 0x1F) および文字 " * : < > ? \ | の使用が禁止されています。パスの長さは約 32767 文字までですが、Windows カーネルは長さ 259 文字までのパスのみをサポートします.さらに、Windows は MS-DOS デバイス名 AUX、CLOCK$、COM1、COM2、COM3、COM4、COM5、COM6、 COM7、COM8、COM9、CON、LPT1、LPT2、LPT3、LPT4、LPT5、LPT6、LPT7、LPT8、LPT9、NUL、PRN、およびこれらの名前に任意の拡張子 (たとえば、AUX.txt) を使用する場合を除きます。長い UNC パス (例: \.\C:\nul.txt または \?\D:\aux\con) (実際、拡張子が指定されている場合は CLOCK$ を使用できます)。これらの制限は Windows にのみ適用されます。たとえば、Linux では、" * : < > ? \ | NTFSでも。
可能なすべての文字を明示的に含めるのではなく、正規表現を実行して不正な文字の存在を確認し、エラーを報告することができます。理想的には、アプリケーションはユーザーが望むとおりにファイルに名前を付け、エラーに遭遇した場合にのみファウルを叫ぶ必要があります。
これを使用して、例外をスローせずにファイル名の無効な文字を取り除きます。
private static readonly Regex InvalidFileRegex = new Regex(
string.Format("[{0}]", Regex.Escape(@"<>:""/\|?*")));
public static string SanitizeFileName(string fileName)
{
return InvalidFileRegex.Replace(fileName, string.Empty);
}
問題は、パス名が有効な Windows パスであるかどうか、またはコードが実行されているシステムで有効かどうかを判断しようとしているのかということです。? 後者の方が重要だと思うので、個人的には、フルパスを分解して _mkdir を使用してファイルが属するディレクトリを作成してから、ファイルを作成しようとするでしょう。
このようにして、パスに有効な Windows 文字のみが含まれているかどうかだけでなく、このプロセスで書き込むことができるパスを実際に表しているかどうかもわかります。
また、CON、PRN、AUX、NUL、COM#、およびその他のいくつかは、拡張子を問わず、どのディレクトリでも正当なファイル名ではありません。
他の回答を補完するために、考慮すべきいくつかの追加のエッジ ケースを次に示します。
名前に「[」または「]」文字が含まれるファイルにワークブックを保存すると、Excel で問題が発生する可能性があります。詳細については、 http://support.microsoft.com/kb/215205を参照してください。
Sharepoint には、追加の一連の制限があります。詳細については、 http://support.microsoft.com/kb/905231を参照してください。
MSDNから、許可されていない文字のリストを次に示します。
Unicode 文字および拡張文字セット (128 ~ 255) の文字を含む、現在のコード ページのほぼすべての文字を名前に使用します。ただし、次の文字は除きます。
- 次の予約文字は使用できません: < > : " / \ | ? *
- 整数表現が 0 ~ 31 の範囲にある文字は使用できません。
- ターゲット ファイル システムで許可されていないその他の文字。
これはすでに回答済みの質問ですが、「その他のオプション」のために、理想的ではない質問を次に示します。
(通常、例外をフロー制御として使用することは「悪いこと」であるため、理想的ではありません)
public static bool IsLegalFilename(string name)
{
try
{
var fileInfo = new FileInfo(name);
return true;
}
catch
{
return false;
}
}
この状況では、正規表現はやり過ぎです。この方法は、および とString.IndexOfAny()
組み合わせて使用できます。Path.GetInvalidPathChars()
Path.GetInvalidFileNameChars()
Path.GetInvalidXXX()
また、どちらのメソッドも内部配列のクローンを作成し、そのクローンを返すことに注意してください。したがって、これを何度も (何千回も) 行う場合は、無効な chars 配列のコピーをキャッシュして再利用することができます。
また、宛先ファイル システムも重要です。
NTFS では、特定のディレクトリに作成できないファイルがあります。ルートで EG $Boot
Path.GetFullPath() を使用することをお勧めします
string tagetFileFullNameToBeChecked;
try
{
Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
// invalid chars found
}
Windows のファイル名はかなり制限がないので、実際にはそれほど問題にならないかもしれません。Windows で許可されていない文字は次のとおりです。
\ / : * ? " < > |
これらの文字が存在するかどうかを確認する式を簡単に作成できます。ただし、より良い解決策は、ユーザーが望むようにファイルに名前を付けて、ファイル名が固執しない場合に警告することです。
このチェック
static bool IsValidFileName(string name)
{
return
!string.IsNullOrWhiteSpace(name) &&
name.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 &&
!Path.GetFullPath(name).StartsWith(@"\\.\");
}
無効な文字 (<>:"/\|?*
および ASCII 0-31) を含む名前と、予約済みの DOS デバイス ( CON
、NUL
、COMx
) を除外します。と一貫して、先頭のスペースとすべてドット名を使用できますPath.GetFullPath
。(私のシステムでは先頭にスペースがあるファイルの作成は成功します)。
Windows 7 でテスト済みの .NET Framework 4.7.1 を使用。