reemplazar - ¿Existe un método Java multiplataforma para eliminar el nombre de archivo de los caracteres especiales?
reemplazar ñ y acentos java (7)
Estoy haciendo una aplicación multiplataforma que cambia el nombre de los archivos en función de los datos recuperados en línea. Me gustaría desinfectar las cadenas que tomé de una API web para la plataforma actual.
Sé que las diferentes plataformas tienen diferentes requisitos de nombre de archivo, por lo que me preguntaba si hay una forma multiplataforma para hacer esto.
Editar: en plataformas Windows, no puede tener un signo de interrogación ''?'' en un nombre de archivo, mientras que en Linux, puede. Los nombres de los archivos pueden contener dichos caracteres y me gustaría que las plataformas que los admiten los mantengan, pero en caso contrario, elimínelos.
Además, preferiría una solución Java estándar que no requiera bibliotecas de terceros.
Aquí está el código que uso:
public static String sanitizeName( String name ) {
if( null == name ) {
return "";
}
if( SystemUtils.IS_OS_LINUX ) {
return name.replaceAll( "/+", "" ).trim();
}
return name.replaceAll( "[/u0001-/u001f<>:/"/////|?*/u007f]+", "" ).trim();
}
SystemUtils
es de Apache commons-lang3
Como se sugiere en otra parte, esto no suele ser lo que quieres hacer. Por lo general, es mejor crear un archivo temporal utilizando un método seguro como File.createTempFile ().
No debe hacer esto con una lista blanca y solo mantener "buenos" caracteres. Si el archivo está formado únicamente por caracteres chinos, le quitará todo. No podemos usar una lista blanca por esta razón, tenemos que usar una lista negra.
Linux prácticamente permite cualquier cosa que pueda ser un verdadero dolor. Limitaría a Linux a la misma lista que limitas a Windows para que te ahorres dolores de cabeza en el futuro.
Usando este fragmento de C # en Windows, produje una lista de caracteres que no son válidos en Windows. Hay bastantes más personajes en esta lista de los que puede pensar (41), por lo que no recomendaría tratar de crear su propia lista.
foreach (char c in new string(Path.GetInvalidFileNameChars()))
{
Console.Write((int)c);
Console.Write(",");
}
Aquí hay una clase Java simple que ''limpia'' un nombre de archivo.
public class FileNameCleaner {
final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
static {
Arrays.sort(illegalChars);
}
public static String cleanFileName(String badFileName) {
StringBuilder cleanName = new StringBuilder();
for (int i = 0; i < badFileName.length(); i++) {
int c = (int)badFileName.charAt(i);
if (Arrays.binarySearch(illegalChars, c) < 0) {
cleanName.append((char)c);
}
}
return cleanName.toString();
}
}
EDITAR: Como Stephen sugirió, probablemente también debería verificar que estos accesos a archivos solo ocurran dentro del directorio que permita.
La siguiente respuesta tiene un código de muestra para establecer un contexto de seguridad personalizado en Java y luego ejecutar el código en esa ''caja de arena''.
Esto se basa en la respuesta aceptada por que funciona bien siempre y cuando no encuentres ningún personaje fuera del plano multilingüe básico . Si necesita soporte total de Unicode (¿y quién no?) Use este código que es seguro para Unicode:
public class FileNameCleaner {
final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
static {
Arrays.sort(illegalChars);
}
public static String cleanFileName(String badFileName) {
StringBuilder cleanName = new StringBuilder();
int len = badFileName.codePointCount(0, badFileName.length());
for (int i=0; i<len; i++) {
int c = badFileName.codePointAt(i);
if (Arrays.binarySearch(illegalChars, c) < 0) {
cleanName.appendCodePoint(c);
}
}
return cleanName.toString();
}
}
Cambios clave aquí:
- Use codePointCount icw
length
lugar de sololength
- use codePointAt lugar de
charAt
- use appendCodePoint lugar de
append
- No hay necesidad de
char
aint
s. De hecho, nunca deberías lidiar conchar
porque básicamente están rotos por algo que esté fuera del BMP.
Hay una solución Java bastante buena incorporada: Character.isXxx () .
Pruebe Character.isJavaIdentifierPart(c)
:
String name = "name.é+!@#$%^&*(){}][/=?+-_//|;:`~!''/",<>";
StringBuilder filename = new StringBuilder();
for (char c : name.toCharArray()) {
if (c==''.'' || Character.isJavaIdentifierPart(c)) {
filename.append(c);
}
}
El resultado es "name.é $ _".
No está claro a partir de su pregunta, pero ya que está planeando aceptar nombres de rutas de un formulario web (?) Probablemente deba bloquear intentos de renombrar ciertas cosas; por ejemplo, "C: / Archivos de programa". Esto implica que necesita canonicalizar los nombres de ruta para eliminar "." y "..." antes de hacer sus comprobaciones de acceso.
Dado que, no intentaría eliminar personajes ilegales. En su lugar, usaría "new File (str) .getCanonicalFile ()" para generar las rutas canónicas, luego verificará que satisfagan las restricciones de sandboxing, y finalmente use "File.exists ()", "File.isFile ()" , etc. para verificar que el origen y el destino sean kosher y que no sean el mismo objeto del sistema de archivos. Me encargaría de los personajes ilegales al intentar hacer las operaciones y atrapar las excepciones.
Si desea utilizar algo más que [A-Za-z0-9], compruebe las Convenciones de denominación de MS y no olvide filtrar "... Caracteres cuyas representaciones enteras están en el rango de 1 a 31, ... ", como el ejemplo de Aaron Digulla hace. El código, por ejemplo, de David Carboni no sería suficiente para estos caracteres.
o simplemente haz esto:
String filename = "A20/B22b#öA//BC#Ä$%ld_ma.la.xps";
String sane = filename.replaceAll("[^a-zA-Z0-9//._]+", "_");
Resultado: A20_B22b_A_BC_ld_ma.la.xps
Explicación:
[a-zA-Z0-9//._]
coincide con una letra de mayúscula o minúscula, números, puntos y guiones bajos
[^a-zA-Z0-9//._]
es el inverso. es decir, todos los caracteres que no coinciden con la primera expresión
[^a-zA-Z0-9//._]+
es una secuencia de caracteres que no coinciden con la primera expresión
Entonces, cada secuencia de caracteres que no consta de caracteres de az, 0-9 o. _ será reemplazado.