Skrip dengan Swift : Ekstraksi Berkas String
Belum lama, saya diberikan tugas di tempat kerja saya untuk mengekstraksi kopi dari Localizable.strings
ke format excel. Pikir saya ini tugas agaknya membosankan bila dikerjakan dengan cara manual. Maka saya ambil kesempatan ini untuk kembali bermain dengan Swift.
Terilhami dari presentasi Ayaka di Swift Summit, tiap tugas kecil seperti ini ternyata bisa lho dikerjakan dengan Swift. Intinya, walaupun belum ada kode Swift dalam proyek utama kita, bukan berarti kita tidak bisa menyentuh Swift sama sekali.
Membuat dan Menjalankan Skrip dengan Swift
- Pastikan Xcode sudah ter-install
- Buat file swift (saya namakan ’
xtractr.swift
’) - Tambah notasi shebang di baris pertama untuk mengkompilasi seluruh kode dengan swift REPL
1 | #!/usr/bin/env xcrun swift
|
- Gunakan
print()
untuk menampilkan teks di layar console
1 | print("Teks ini dibuat dengan Swift!") |
- Di terminal, ganti file permission menjadi executable
1 2 | // pastikan kita berada di direktorinya xtractr.swift
$ chmod +x xtractr.swift
|
- Jalankan skrip dari terminal
1 2 | $ ./xtractr.swift "Teks ini dibuat dengan Swift!" |
Cukup mudah kan? Setelah hanya menampilkan contoh teks, mari kita buat pengurai Localizable.strings
yang sebenarnya.
Membaca parameter dari terminal
Untuk mendapatkan nama file dari terminal, kita bisa gunakan variabel Process.arguments
. Variabel ini berisi semua parameter yang diketikkan saat dijalankan dari terminal.
Bila ingin melihat parameter yang kita dapatkan dari terminal, ubah skrip kita menjadi seperti di bawah
1 2 | #!/usr/bin/env xcrun swift print(Process.arguments) |
Jalankan kembali di terminal
1 2 | $ ./xtractr.swift tes argumen 123 ["./xtractr.swift", "tes", "argumen", "123"] |
Bisa kita lihat, kata per kata dirangkum dalam list Process.arguments
(termasuk nama programmnya sendiri). Skrip kita hanya akan mengharapkan satu buah parameter, yaitu alamat dari berkas Localizable.strings
itu sendiri. Kita bisa rangkum menjadi sebuah fungsi yang akan mengecek jumlah parameter dan mengambil parameter pertama sebagai filepath.
1 2 3 4 5 6 7 8 9 10 | #!/usr/bin/env xcrun swift func getParameter() -> String { guard Process.arguments.count >= 2 else { return "File tidak ditemukan" } return Process.arguments[1] } print(getParameter()) |
Sebelum mencoba kembali, cari suatu file Localizable.strings
dari salah satu proyek yang sudah ada ke dalam direktori yang aktif di terminal (saya taruh di ~/Desktop
). Jalankan kembali dengan menggunakan nama file yang benar. Coba cek juga tanpa menggunakan parameter dab menggunakan lebih dari satu parameter.
1 2 3 4 5 6 | $ ./xtractr.swift Localizable.strings Localizable.strings $ ./xtractr.swift File tidak ditemukan $ ./xtractr.swift Localizable.strings 123 heyho Localizable.strings |
Membaca teks dari file
Untuk membaca konten teks dari sebuah file, kita bisa gunakan fungsi konstruktor dari NSString
yang menerima parameter filepath dan encoding.
1 | let content = try NSString(contentsOfFile: filepath, encoding: NSUTF8StringEncoding) |
Bisa kita periksa bahwa tipe yang digunakan adalah NSString
dan bukan String
dari Swift. Kita bisa konversi dari tipe satu ke tipe lainnya, namun karena kita menggunakan beberapa perilaku dan method dari NSString
maka kita biarkan dulu dan konversi ke String
hanya saat diperlukan.
Mengurai teks dari Localizable.strings
Penguraian akan menggunakan NSRegularExpression
yang akan menemukan semua string dalam file yang berformat : "<key>" = "<value>";
.
1 2 | let regex = try NSRegularExpression(pattern: "\"(.+?)\"\\s*=\\s*\"(.+?)\"\\s*;", options: .CaseInsensitive) let matches = regex.matchesInString((query as String), options: .WithTransparentBounds, range: NSMakeRange(0, query.length)) |
Variabel matches
akan berisi array dari objek NSTextCheckingResult
. NSTextCheckingResult
mempunyai sebuah list lagi yang berisi NSRange
yang menunjukan lokasi-lokasi dari string yang cocok dengan format regex yang kita berikan. Untuk mendapatkan semua string yang dari sebuah NSTextCheckingResult
kita harus mengaksesnya dengan rangeAtIndex
1 2 3 4 5 6 | var strings = [String]() for index in 0..<(match.numberOfRanges) { let range = match.rangeAtIndex(index) strings.append(query.substringWithRange(range) as String) } return strings |
Setiap array string yang kita dapatkan akan berjumlah tiga, yaitu dalam kesatuan format ("<key>" = "<value>";
), key-nya (<key>
) dan terakhir value dari key tersebut (<value>
). Kita hanya akan menggunakan 2 string terakhir dari setiap array string kita.
Terakhir kita akan mengkonversi semua pasangan <key, value>
kita ke dalam format yang bisa dibaca Excel. Format yang paling mudah adalah format csv atau comma separated value. Intinya tiap kolom akan dipisahkan dengan koma; “<key>,<value>\n
”
Bila kita gabung seluruh proses ini menjadi satu kesatuan, fungsi pengurai akan terlihat seperti berikut
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 | func parse(query: NSString) throws -> String { let regex = try NSRegularExpression(pattern: "\"(.+?)\"\\s*=\\s*\"(.+?)\"\\s*;", options: .CaseInsensitive) let matches = regex.matchesInString((query as String), options: .WithTransparentBounds, range: NSMakeRange(0, query.length)) let results = matches // transformasi dari NSTextCheckingResult menjadi array String .map { match -> [String] in var strings = [String]() for index in 0..<(match.numberOfRanges) { let range = match.rangeAtIndex(index) strings.append(query.substringWithRange(range) as String) } return strings } // periksa apakah pasti ada tiga atau lebih string .filter { $0.count >= 3 } // transformasi dari array string menjadi key value yang terpisah oleh koma .reduce("") { (initial, strings) -> String in return initial + "\(strings[1]),\(strings[2])\n" } return results } |
Hasil akhir
Kode akhir bisa lihat di sini, berikut dengan penanganan error yang lebih lengkap.
Namun saat kita jalankan, skrip ini hanya akan menampikan konten csv di dalam terminal. Untuk menyimpannya ke dalam file, kita harus pass hasil cetak tersebut langsung di terminal dengan format “> nama_file.csv
”.
1 2 | $ ./xtractr.swift Localizable.strings # hanya mencetak di terminal $ ./xtractr.swift Localizable.strings > extracted.csv # mencetak ke dalam sebuah file extracted.csv |
Walau tugas saya saat itu cukup remeh namun tugas ini jadi lebih menarik dan lebih menyenangkan karena saya menantang diri saya dengan menggunakan Swift. Sampai jumpa di skrip-skrip Swift selanjutnya!
Update 10-11-2015
Kalau perlu contoh lain yang lebih advance, bisa cek postingan Ayaka tentang bagaimana dia membuat halaman acknowledgement dengan membaca file Cocoapods and Carthage. Keren cuy!