2011-01-19 8 views
7

Ecco una versione che ho scritto usando divisa:espressione Scala per sostituire un'estensione di file in una stringa

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

Questo trasforma per esempio foo.bar.coffee in foo.bar.js.

Quello che mi piace:

  • funziona
  • non si basa su cose come indexOf()
  • ci si sente funzionale;)

Quello che non mi piace:

  • non è così breve come mi piacerebbe
  • potrebbe confondere alcuni lettori

Come posso scrivere una versione ancora più semplice/semplice?

AGGIORNAMENTO: ottime risposte qui sotto! In breve:

  • sembra che il mio approccio originale al di sopra non era male, anche se non copre alcuni casi angolo, ma questo è risolvibile con un'espressione più a lungo se è necessario per coprire quelli
  • un'altra, approccio un po 'più corto utilizza espressioni regolari, che sarà più o meno leggibile a seconda del vostro sfondo espressione regolare
  • una sintassi leggermente più corta per l'approccio originale (casi d'angolo non coperti) si legge:

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

+2

Per la cronaca, questo è molto semplice per me. –

+1

Sono d'accordo con Rafe. Personalmente mi piace meglio delle versioni di espressioni regolari. Tuttavia, non funziona bene con i nomi di file che non hanno estensione. Puoi sbarazzarti di '++ Seq (" js ")' sostituendolo con ': +" js "', a proposito. – Madoc

+0

Ricorda che, a seconda di cosa vuoi fare, i file con estensioni doppie non vengono trattati "correttamente", ad es. 'x.tar.gz' diventa' x.tar.js' – Raphael

risposta

9

temo che in realtà hanno per renderlo più di fare ciò che è probabilmente la più sensata cosa robusto:

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

Kinda inaspettata di perdere il nome del file (almeno se si' re un utente finale)!

Proviamo regex:

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

non ha perso il nome del file, ma non c'è alcuna estensione sia. Ack.

Diciamo fissarlo:

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 espressioni regolari:

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 

(Si noti il ​​diverso comportamento sul caso angolo dove il nome del file termina con periodi.)

+0

Quello che trovo un po 'uno spreco è che tutte le sottostringhe per le sezioni delimitate del periodo del nome del file vengono creati e quindi concatenati in seguito. Per evitare ciò, sarebbe opportuno usare 'lastIndexOf', a cui l'OP non piaceva. Tuttavia, penso che sarebbe una buona idea. – Madoc

+0

@Madoc - Presumibilmente stai facendo queste operazioni perché vuoi lavorare con i file. Quanto dura un'operazione di file tipica rispetto a split + mkString? –

+0

Mi aspetto che la VM ottimizzi questo aspetto, comunque. – Raphael

3

Sarà sufficiente una semplice regex sostitutiva?

come:

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

Haha, ciao Eric. Hai 12 secondi su di me, ma il mio è più corto di 2 caratteri. ;) – Synesso

+0

Sapevo che dovevo migliorare il mio regex fu, ... – Eric

2

Si può sempre utilizzare il metodo replaceAll su java.lang.String

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

E 'più breve, ma meno leggibile.

2

Cosa c'è di sbagliato con lastIndexOf?

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

Naturalmente, se si desidera mantenere il nome del file quando non contiene alcun punto, è necessario fare un po 'di più

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

Niente di assolutamente sbagliato con gli indici. Ma in sostanza stavo cercando di vedere dove ti portano altri approcci. È un po 'come la differenza tra l'uso di 'for (i = 0; i ebruchez

2

Così, vado per la velocità qui. Come succede, substring è un tempo costante perché semplicemente non copia la stringa. Quindi,

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

Questo utilizza una chiusura, che lo rallenterà un po '. Più veloce:

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

    addJSAt(fileName lastIndexOf '.') 
} 

EDIT: Come accade, Java ora fa copiare la stringa su substring.

+0

C'è qualcosa di sbagliato quando stai andando alla velocità e sto scrivendo i pattern match e sto dicendo non preoccuparti .... –

+0

@Rex Hey, non è che tu mi abbia lasciato qualcos'altro per cui andare ... :-) –

+0

I sapere che questo è antico, chiedendosi solo se ci sono prestazioni o altri motivi per usare una funzione nidificata piuttosto che qualcosa come 'def addJS (fileName: String) = { val index = fileName lastIndexOf '.' (if (indice> = 0) fileName sottostringa (0, indice) else fileName ) + ".js" } ' – Davos

2

molto facile con lastIndexOf, e il lavoro con il nome del file che contiene più di un punto

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

val fileName = "foo.bar.coffee" 

getFileNameWithoutExtension(fileName) + ".js" 

risultato è foo.bar.js

Problemi correlati