2011-01-19 6 views
7

Aquí está una versión que escribí usando dividida:expresión Scala para reemplazar una extensión de archivo en una cadena

fileName.split('.').init ++ Seq("js") mkString "." 

Esto transforma, por ejemplo, foo.bar.coffee en foo.bar.js.

lo que me gusta:

  • que funciona
  • no se basa en cosas como indexOf()
  • se siente funcional;) ​​

Lo que no me gustan:

  • no es tan corto como yo esperaría
  • que podría confundir a algunos lectores

¿Cómo puedo escribir una versión aún más simple/sencillo?

ACTUALIZACIÓN: ¡Grandes respuestas a continuación! En resumen:

  • parece como si mi enfoque original anterior no estaba mal aunque no cubre algunos casos de esquina, pero eso es corregible con una expresión más tiempo si se necesita para cubrir los
  • otra, enfoque ligeramente más corto utiliza expresiones regulares, que serán más o menos dependiendo de sus antecedentes legible expresión regular
  • una sintaxis ligeramente más corto para el enfoque original (casos de esquina que no están cubiertos) lee:

    fileName.split('.').init :+ "js" mkString "."

+2

Para el registro, esto es muy sencillo para mí. –

+1

Estoy de acuerdo con Rafe. Personalmente me gusta más que las versiones de expresiones regulares. Sin embargo, no funciona bien con nombres de archivo que no tienen extensión. Puede deshacerse de '++ Seq (" js ")' reemplazándolo por ': +" js "', por cierto. – Madoc

+0

Tenga en cuenta que, según lo que desee hacer, los archivos con doble extensión no se tratan "correctamente", p. 'x.tar.gz' se convierte en' x.tar.js' – Raphael

Respuesta

9

Me temo que realmente tiene que hacer que sea más largo para hacer lo que es probablemente la más sensata cosa robusta:

scala> "oops".split('.').init ++ Seq("js") mkString "." 
res0: String = js 

Un poco inesperado a perder el nombre de su archivo (al menos si' re un usuario final)!

Vamos a tratar de expresiones regulares:

scala> "oops".replaceAll("\\.[^.]*$", ".js") 
res1: java.lang.String = oops 

no perdió el nombre del archivo, pero no hay ninguna extensión tampoco. Ack.

Vamos a arreglarlo:

def extensor(orig: String, ext: String) = (orig.split('.') match { 
    case xs @ Array(x) => xs 
    case y => y.init 
}) :+ "js" mkString "." 

scala> extensor("oops","js") 
res2: String = oops.js 

scala> extensor("oops.txt","js") 
res3: String = oops.js 

scala> extensor("oops...um...","js") 
res4: String = oops...js 

O con expresiones regulares:

scala> "oops".replaceAll("\\.[^.]*$", "") + ".js" 
res5: java.lang.String = oops.js 

scala> "oops.txt".replaceAll("\\.[^.]*$", "") + ".js" 
res6: java.lang.String = oops.js 

scala> "oops...um...".replaceAll("\\.[^.]*$", "") + ".js" 
res7: java.lang.String = oops...um...js 

(Tenga en cuenta el comportamiento diferente en el caso esquina donde el nombre del archivo termina con períodos.)

+0

Lo que me parece un desperdicio es que todas las subcadenas para las secciones delimitadas por el período del nombre del archivo se están creando, y luego se concatenarán nuevamente. Para evitar esto, sería bueno usar 'lastIndexOf', que al OP no le gustó. Sin embargo, creo que sería una buena idea. – Madoc

+0

@Madoc: presumiblemente estás haciendo estas operaciones porque quieres trabajar con archivos. ¿Cuánto dura una operación de archivo típica en comparación con una división + mkString? –

+0

Esperaría que la VM optimice esto de todos modos. – Raphael

3

¿Será suficiente un simple reemplazo de regex?

igual:

scala> "package.file.java".replaceAll("(\\.[^\\.]*$)", ".rb") 
scala> "package.file.rb" 
+0

Haha, hola Eric. Tienes 12 segundos para mí, pero el mío es 2 caracteres más corto. ;) – Synesso

+0

Sabía que tenía que mejorar mi expresión regular, ... – Eric

2

Siempre se puede utilizar el método replaceAll en java.lang.String

scala> "foo.bar.coffee".replaceAll("\\.[^.]*$", ".js") 
res11: java.lang.String = foo.bar.js 

Es más corto, pero menos legible.

2

¿Qué pasa con lastIndexOf?

fileName.take(1 + fileName.lastIndexOf(".")) + "js" 

Por supuesto, si desea mantener el nombre de archivo al que no contiene ningún punto, es necesario hacer un poco más

(if (fileName.contains('.')) fileName.take(fileName.lastIndexOf(".")) 
else fileName) + ".js" 
+0

Nada absolutamente malo con los índices. Pero, en esencia, estaba tratando de ver hacia dónde te llevan otros enfoques. Es un poco como la diferencia entre usar 'for (i = 0; i ebruchez

2

Por lo tanto, voy a ir para la velocidad aquí. Da la casualidad que substring es un tiempo constante porque simplemente no copia la cadena. Por lo tanto,

((index: Int) => (
) + ".js")(fileName lastIndexOf '.') 

Esto utiliza un cierre, que lo ralentizará un poco. Más rápido:

def addJS(fileName: String) = { 
    def addJSAt(index: Int) = (
     if (index >= 0) fileName substring (0, index) 
     else fileName 
    ) + ".js" 

    addJSAt(fileName lastIndexOf '.') 
} 

EDIT: Si llega el caso, Java ahora hace copiar la cadena de substring.

+0

Algo anda mal cuando vas por velocidad y estoy escribiendo coincidencias de patrones y diciendo que no te preocupes ... –

+0

@Rex Oye, no es como si me hubieras dejado algo más por ... :-) –

+0

I Sé que esto es antiguo, solo me pregunto si hay rendimiento u otra razón para usar una función anidada en lugar de algo como 'def addJS (fileName: String) = { val index = fileName lastIndexOf '.' (if (index> = 0) subcadena fileName (0, índice) else nombre_de_archivo ) + ".js" } ' – Davos

2

muy fácil con lastIndexOf, y el trabajo con el nombre de archivo que contiene más de un punto

def getFileNameWithoutExtension(fileName: String): String = { 
    fileName.dropRight(fileName.length - fileName.lastIndexOf(".")) 
} 

val fileName = "foo.bar.coffee" 

getFileNameWithoutExtension(fileName) + ".js" 

resultado es foo.bar.js

Cuestiones relacionadas