我需要从用户输入的名称生成文件名。这些名称可以是任何语言。例如:
这些是使用输入值,因此我无法保证名称不包含文件名无效的字符。
用户将从浏览器下载这些文件,因此我需要确保文件名在所有配置的所有操作系统上都有效。
我目前正在为英语国家/地区执行此操作,只需使用简单的正则表达式删除所有非字母数字字符:
string = string.replaceAll("[^a-zA-Z0-9]", "");
string = string.replaceAll("\\s+", "_")
一些示例转化:
显然这在国际上不起作用。
我考虑过查找/生成所有文件系统中无效的所有字符的黑名单,并从名称中删除这些字符。我一直无法找到一份全面的清单。
如果可能的话,我更喜欢在公共库中使用现有代码。我想这是一个已经解决的问题,但我无法找到一个国际化的解决方案。
文件名是供用户下载文件的,不适合我。我不打算存储这些文件。这些文件是服务器根据数据库中的数据请求动态生成的。文件名是为了方便下载文件的人。
答案 0 :(得分:4)
正则表达式[^a-zA-Z0-9]
将过滤非ASCII字符,这些字符将省略Unicode字符或128个以上代码点以上的字符。
假设您要通过使用下划线(? \ / : | < > *
)替换无效的文件名字符(例如_
)来过滤有效文件名的用户输入:
import java.io.UnsupportedEncodingException;
public class ReplaceI18N {
public static void main(String[] args) {
String[] names = {
"John Smith",
"高岡和子",
"محمد سعيد بن عبد العزيز الفلسطيني",
"|J:o<h>n?Sm\\it/h*",
"高?岡和\\子*",
"محمد /سعيد بن عبد ?العزيز :الفلسطيني\\"
};
for(String s: names){
String u = s;
try {
u = new String(s.getBytes(), "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
u = u.replaceAll("[\\?\\\\/:|<>\\*]", " "); //filter ? \ / : | < > *
u = u.replaceAll("\\s+", "_");
System.out.println(s + " = " + u);
}
}
}
输出:
John Smith = John_Smith
高岡和子 = 高岡和子
محمد سعيد بن عبد العزيز الفلسطيني = محمد_سعيد_بن_عبد_العزيز_الفلسطيني
|J:o<h>n?Sm\it/h* = _J_o_h_n_Sm_it_h_
高?岡和\子* = 高_岡和_子_
محمد /سعيد بن عبد ?العزيز :الفلسطيني\ = محمد_سعيد_بن_عبد_العزيز_الفلسطيني_
即使使用Unicode字符,有效的文件名也可以在支持使用正确Unicode字体的UTF-8编码的任何网页上显示。
此外,在支持Unicode的任何操作系统文件系统上,每个文件都是正确的名称(在Windows XP,Windows 7上测试正常)。
但是,如果您想将每个有效文件名作为URL字符串传递,请确保使用URLEncoder
正确编码,然后使用URLDecoder
对每个编码的网址进行解码。
答案 1 :(得分:0)
让输入在没有正确清理的情况下确定文件名似乎容易受到安全攻击。您可以使用哈希函数(SHA-1,MD5)生成有效的文件名。请注意,您无法从哈希中获取原始名称。
此外,如果您可以拥有一个简单的查找表,则可以为名称指定特殊标识符(如序列号或GUID),并使用标识符作为文件名。
另一件事,您是否考虑过同音异义词?
答案 2 :(得分:0)
将文件名编码为UTF-8,然后对结果进行URL编码。
'高岡和子' -> '%E9%AB%98%E5%B2%A1%E5%92%8C%E5%AD%90'
答案 3 :(得分:0)
Windows appears to support unicode file names,我知道Linux确实如此,显然OS X也是如此。据推测,编写良好的文件会在保存之前修复文件名中的无效字符。
您似乎应该能够使用unicode文件名。是否有某些操作系统或浏览器无效?
答案 4 :(得分:0)
我的建议是将其作为要求,使您的应用程序在支持Unicode文件名的平台上运行。大多数人都这样做了。
我认为从Unicode映射到(未指定的)受限字符集是不可行的,同时仍保留人类可读性和原始含义并避免冲突。实际上,甚至不可能从Latin-1到ASCII进行映射。
如果您的应用程序 在不支持Unicode文件名的平台上运行,那么在某些情况下您需要牺牲人类可读性和/或文件名中的含义。此外,请考虑(例如)ASCII化中文字符或Cyrilic字母或带有重音符号的字母是否可供您的最终用户接受。
我要做的是为用户提供两个选项供选择:
对上传文件使用Unicode文件名的选项。这应该是默认设置,因为大多数用户的机器都支持此功能。
使用与原始字符串/文本无关的生成名称的后备选项。
实际上,如果用户的机器不支持Unicode,那么处理未使用机器的本机编码编码的文本名称将会遇到很大问题。没有完全可靠的方法来找出它是什么。即使你有一种半可靠的方法来解决...在服务器端...将所有Unicode映射到该编码的问题是难以处理的。
最好鼓励用户将他/她的操作系统升级为支持Unicode的操作系统。
答案 5 :(得分:0)
总结和解释@eee的答案......
String sanitizeFilename(String unsanitized) {
return unsanitized
.replaceAll("[\\?\\\\/:|<>\\*]", " ") // filter out ? \ / : | < > *
.replaceAll("\\s", "_"); // white space as underscores
}
(不将多个空格合并为一个!)