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]. Символы разрешены в именах файлов, но они могут нуждаться в специальном обращении пользователей, а некоторые программы имеют ошибки, вызванные их существованием.