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

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

Эти символы:

 \ / : * ? "  | 

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

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

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

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

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

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

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

Ответ 1

Правила имени файла Windows сложны. Вы только царапаете поверхность.

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

                                    (yes, that an empty string)
.
.a
a.
 a                                  (that 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]

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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

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

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

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

Ответ 5

Java имеет функцию replaceAll, но каждый язык программирования имеет способ сделать что-то подобное. Например, Perl использует переключатель g для обозначения глобальной замены. Функция Python sub позволяет указать количество произведенных замен. Если по какой-то причине ваш язык не имеет эквивалента, вы всегда можете сделать что-то вроде этого:

while (filename.matches(bad_characters)
  filename.replace(bad_characters, "")

Ответ 6

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

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

Ответ 10

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

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

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