Tutti i programmatori hanno avuto a che fare con operazioni di cerca/sostituisci nel testo, e di utilities per questo tipo di operazioni, in effetti ce ne sono parecchie. Gli utenti Linux hanno a disposizione molti strumenti nativi potenti e flessibili, chi utilizza Windows invece, sebbene possa installare linguaggi di script di terze parti come Perl o PHP, se vuole utilizzare strumenti nativi deve utilizzare VBScript e Windows Script Host (WSH). Per essere precisi, non è del tutto necessario conoscere VBScript, perché la piattaforma WSH è language-indipendent, dunque altri linguaggi come javascript sono pure supportati.
Fatta questa piccola premessa, torniamo al tema delle sostituzioni nel testo. Ho trovato su Internet numerosi script per la ricerca e la sostituzione di testo sia in un unico file che in file multipli (problema comune per i webmaster), ma non ho trovato molto per poter sostituire velocemente una lunga lista di stringhe, con un’altra all’interno di un certo file di testo. Un esempio pratico potrebbe essere un file CSV che contiene una colonna di codici da sostituire con la corrispettiva lista di id estratta dalla tabella di un database. Questo processo potrebbe risultare utile per velocizzare l’importazione di certi dati in tabelle di database.
Ho assemblato questo piccolo script VBScript utilizzando porzioni di codice reperite nella rete, ed aggiungendo alcune personalizzazioni.
Queste sono le caratteristiche:
- Lo script carica da un file CSV che utilizza la “,” come separatore, un array di stringhe da cercare e il corrispettivo array di stringhe sostitutive
- Apre il file con il testo da elaborare ed effettua le sostituzioni
- Salva il testo modificato in un nuovo file in modo da preservare l’originale
Ecco il codice:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
| ' VB Script Document
option explicit
Dim FileName, FileContents, dFileContents, FileFindReplace
Dim oFSO, oTextFile, arrList, items, keys
Dim sNextLine, tmp, i
FileName = WScript.Arguments(0)
FileFindReplace = WScript.Arguments(1)
'Read source text file
FileContents = GetFile(FileName)
dFileContents = FileContents
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oTextFile = oFSO.OpenTextFile(FileFindReplace, 1)
Set arrList = CreateObject("Scripting.Dictionary")
Do Until oTextFile.AtEndOfStream
sNextLine = oTextFile.Readline
tmp = Split(sNextLine , ",")
arrList.Add tmp(0), tmp(1)
Loop
items = arrList.Items
keys = arrList.Keys
'Loop through Items array
For i = 0 To UBound(items)
'replace all string In the source file
dFileContents = replace(dFileContents, items(i), keys(i), 1, -1, 1)
Next
'Compare source And result
if dFileContents <> FileContents Then
'write result If different
WriteFile NewFileName(FileName), dFileContents
Wscript.Echo "Replace done."
Else
Wscript.Echo "Searched string Not In the source file"
End If
'Read text file
Function GetFile(FileName)
If FileName<>"" Then
Dim FS, FileStream
Set FS = CreateObject("Scripting.FileSystemObject")
on error resume Next
Set FileStream = FS.OpenTextFile(FileName)
GetFile = FileStream.ReadAll
End If
End Function
'Write string As a text file.
Function WriteFile(FileName, Contents)
Dim OutStream, FS
on error resume Next
Set FS = CreateObject("Scripting.FileSystemObject")
Set OutStream = FS.OpenTextFile(FileName, 2, True)
OutStream.Write Contents
End Function
'Compose new file name with date and time.
Function NewFileName(sFileName)
Dim MyDate, arrNewFileName, sNewFileName, sExt
arrNewFileName = Split(sFileName, "\")
sNewFileName = arrNewFileName(Ubound(arrNewFileName))
MyDate = Replace(Now, "/", "")
MyDate = Replace(MyDate, ".", "")
MyDate = Replace(MyDate, " ", "_")
If InStr(sNewFileName, ".") Then
sExt = Right(sNewFileName, 3)
sNewFileName = Left(sNewFileName,(Len(sNewFileName) - 4))
sNewFileName = sNewFileName & "_" & MyDate & "." & sExt
Else
sNewFileName = sNewFileName & "_" & MyDate
End If
NewFileName = sNewFileName
End Function |
' VB Script Document
option explicit
Dim FileName, FileContents, dFileContents, FileFindReplace
Dim oFSO, oTextFile, arrList, items, keys
Dim sNextLine, tmp, i FileName = WScript.Arguments(0)
FileFindReplace = WScript.Arguments(1) 'Read source text file
FileContents = GetFile(FileName)
dFileContents = FileContents Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oTextFile = oFSO.OpenTextFile(FileFindReplace, 1)
Set arrList = CreateObject("Scripting.Dictionary")
Do Until oTextFile.AtEndOfStream
sNextLine = oTextFile.Readline
tmp = Split(sNextLine , ",")
arrList.Add tmp(0), tmp(1)
Loop
items = arrList.Items
keys = arrList.Keys
'Loop through Items array
For i = 0 To UBound(items)
'replace all string In the source file
dFileContents = replace(dFileContents, items(i), keys(i), 1, -1, 1)
Next 'Compare source And result
if dFileContents <> FileContents Then
'write result If different
WriteFile NewFileName(FileName), dFileContents
Wscript.Echo "Replace done."
Else
Wscript.Echo "Searched string Not In the source file"
End If 'Read text file
Function GetFile(FileName)
If FileName<>"" Then
Dim FS, FileStream
Set FS = CreateObject("Scripting.FileSystemObject")
on error resume Next
Set FileStream = FS.OpenTextFile(FileName)
GetFile = FileStream.ReadAll
End If
End Function 'Write string As a text file.
Function WriteFile(FileName, Contents)
Dim OutStream, FS
on error resume Next
Set FS = CreateObject("Scripting.FileSystemObject")
Set OutStream = FS.OpenTextFile(FileName, 2, True)
OutStream.Write Contents
End Function 'Compose new file name with date and time.
Function NewFileName(sFileName)
Dim MyDate, arrNewFileName, sNewFileName, sExt
arrNewFileName = Split(sFileName, "\")
sNewFileName = arrNewFileName(Ubound(arrNewFileName))
MyDate = Replace(Now, "/", "")
MyDate = Replace(MyDate, ".", "")
MyDate = Replace(MyDate, " ", "_")
If InStr(sNewFileName, ".") Then
sExt = Right(sNewFileName, 3)
sNewFileName = Left(sNewFileName,(Len(sNewFileName) - 4))
sNewFileName = sNewFileName & "_" & MyDate & "." & sExt
Else
sNewFileName = sNewFileName & "_" & MyDate
End If
NewFileName = sNewFileName
End Function
Vediamo la sua applicazione in un file di prova (prova.txt) che contiene il seguente testo:
uno
due
due
tre
tre
quattro
cinque
cinque
sei
sette
otto
otto
nove
dieci
dieci
dieci
dieci
nel quale vogliamo convertire le stringhe in numeri (per fare questo in realtà ci sarebbero anche altri metodi più veloci!)
Il file per le sostituzioni (decodificaprova.txt) sarà
1,uno
2,due
3,tre
4,quattro
5,cinque
6,sei
7,sette
8,otto
9,nove
10,dieci
lanciamo lo script che chiameremo find_replace.vbs, indicando come primo parametro il file su cui effettuare le sostituzioni e come secondo parametro il file di decodifica:
C:\percorso_del_file\find_replace.vbs" prova.txt decodificaprova.txt
Il risultato (in questo caso: prova_18052008_104851.txt) prende il nome del file originale + una stringa che rappresenta la data e l’ora di sistema:
1
2
2
3
3
4
5
5
6
7
8
8
9
10
10
10
10
NOTE:
Il file di decodifica deve avere una prima colonna con l’elenco delle sostituzioni ed una seconda colonna con l’elenco delle stringhe da ricercare. E’ molto importante evitare stringhe ambigue, ad esempio se si vuole sostituire l’articolo “la” con “una” e nel testo esiste la parola “lana”, questa verrà convertita in “unana”! In questi casi è bene inserire dei delimitatori come ad esempio il carattere #
Requisiti:
E’ necessario che sia installato il supporto WSH, la versione più recente è la 5.7
Conclusioni:
Lo script si è rivelato molto veloce ed efficiente, sarebbe interessante migliorarlo per ottenere una maggiore flessibilità e sicurezza, ma il suo scopo era quello di risolvere velocemente un problema che mi avrebbe fatto perdere molto tempo se affrontato manualmente, e lo ha raggiunto!
Riferimenti ed approfondimenti: