Regex для замены символов, которые Windows не принимает в имени файла

Я пытаюсь создать регулярное выражение, которое обнаружит любой символ, который Windows не принимает как часть имени файла (это то же самое для других ОС? Честно говоря, не знаю).

эти символы:

  / : * ? "  | 

в любом случае, это то, что у меня есть: [/:*?"<>|]

тестер на http://gskinner.com/RegExr/ показывает, что это работает. Для строки Allo*ha на * символ загорается, сигнализируя, что он найден. Должен ли я войти Allo**ha однако, только первый * загорается. Поэтому я думаю, что мне нужно изменить это регулярное выражение, чтобы найти все появления упомянутых персонажей, но я не уверен.

видите ли, на Java мне повезло, что у меня есть функция строку.replaceAll (регулярное выражение строки, замена строки). В описании говорится:

заменяет каждую подстроку этой строки, которая соответствует заданному регулярному выражению с учетом замена.

другими словами, даже если регулярное выражение найдет только первое, а затем прекратит поиск, эта функция все равно найдет их все.

например: String.replaceAll("[/:*?"<>|]","")

однако я не чувствую, что могу рисковать. Кто-нибудь знает, как я могу это продлить?

11 ответов


правила имени файла Windows являются хитрый. Ты только царапаешь поверхность.

например, вот некоторые вещи, которые не являются допустимыми именами файлов, в дополнение к перечисленным вами chracters:

                                    (yes, that's an empty string)
.
.a
a.
 a                                  (that's a leading space)
a                                   (or a trailing space)
com
prn.txt
[anything over 240 characters]
[any control characters]
[any non-ASCII chracters that don't fit in the system codepage,
 if the filesystem is FAT32]

удаление специальных символов в одном подзаголовке regex, например String.replaceAll () недостаточно; вы можете легко получить что-то недопустимое, например пустую строку или трейлинг".’ или ‘ ’. Замена чего-то вроде "[^A-Za-z0-9_.]*" с ‘_’ Было бы лучше первый шаг. Но вам все равно понадобится обработка более высокого уровня на любой платформе, которую вы используете.


поскольку ответа не было достаточно, я сделал это сам. надеюсь, это поможет;)

public static boolean validateFileName(String fileName) {
    return fileName.matches("^[^.\\/:*?\"<>|]?[^\\/:*?\"<>|]*") 
    && getValidFileName(fileName).length()>0;
}

public static String getValidFileName(String fileName) {
    String newFileName = fileName.replace("^\.+", "").replaceAll("[\\/:*?\"<>|]", "");
    if(newFileName.length()==0)
        throw new IllegalStateException(
                "File Name " + fileName + " results in a empty fileName!");
    return newFileName;
}

для записи POSIX-совместимые системы (включая UNIX и Linux) поддерживают все символы, кроме нулевого символа ('') и Слэш ('/') в именах файлов. Специальные символы, такие как пробел и звездочка, должны быть экранированы в командной строке, чтобы они не выполняли свои обычные роли.


Я использую чистое и простое регулярное выражение. Я даю символы, которые могут произойти, и через отрицание "^" я изменяю все другое как знак такого. "_"

String fileName = someString.replaceAll ("[^a-zA-Z0-9\\.\\-]", "_");

например: Если вы не хотите быть в выражения "."затем удалите"\\."

String fileName = someString.replaceAll ("[^a-zA-Z0-9\\-]", "_");


Java имеет функцию replaceAll, но каждый язык программирования имеет способ сделать что-то подобное. Perl, например, использует g переключатель для обозначения глобальной замены. В Python


я извлекаю все символы слова и пробелы из исходной строки, а также удостоверяюсь, что символ пробела отсутствует в конце строки. Вот мой фрагмент кода на Java.

temp_string = original.replaceAll("[^\w|\s]", "");
final_string = temp_string.replaceAll("\s$", "");

думаю, я кому-то помог.


вы можете попробовать разрешить только то, что вы хотите, чтобы пользователь мог ввести, например A-Z, a-z и 0-9.


вы не можете сделать это с одним регулярным выражением, потому что регулярное выражение всегда соответствует подстроке, если вход. Рассмотрим слово Alo*h*a, нет подстроки, которая содержит все *s, а не какой-либо другой символ. Поэтому, если вы можете использовать функцию replaceAll, просто придерживайтесь ее.

кстати, набор запрещенных символов отличается в других ОС.


Я сделал один очень простой способ это работает для меня наиболее распространенных случаях:

// replace special characters that windows doesn't accept
private String replaceSpecialCharacters(String string) {
    return string.replaceAll("[\*/\\!\|:?<>]", "_")
            .replaceAll("(%22)", "_");
}

%22 кодируется, если у вас есть qoute (") в именах файлов.


требуемое регулярное выражение / синтаксис (JS):

.trim().replace(/[\/:*?\"<>|]/g,"").substring(0,240);

если последний бит является необязательным, используйте только тогда, когда вы хотите ограничить длину до 240.

другие полезные функции (JS-файлы):

.toUppperCase();
.toLowerCase();
.replace(/  /g,' ');     //normalising multiple spaces to one, add before substring.
.includes("str");        //check if a string segment is included in the filename
.split(".").slice(-1);   //get extension, given the entire filename contains a .

Windows также не принимает " % " в качестве имени файла.

Если вы создаете общее выражение, которое может повлиять на файлы, которые в конечном итоге будут перемещены в другую операционную систему, я предлагаю вам поместить больше символов, которые могут иметь проблемы с ними.

например, в Linux (многие дистрибутивы я знаю), некоторые пользователи могут иметь проблемы с файлами, содержащими [b]&! ] [ /- () [/b]. Символы разрешены в именах файлов, но они должны быть специально обработаны пользователи и некоторые программы имеют ошибки, вызванные их существованием.