2014年10月1日水曜日

開発環境

Practical Programming: An Introduction to Computer Science Using Python 3 (Pragmatic Programmers) (Paul Gries (著)、Jennifer Campbell (著)、Jason Montojo (著)、Lynn Beighley (編集)、Pragmatic Bookshelf)のChapter 10(Reading and Writing Files)、10.10(Exercises) 8.をSwiftで考えてみる。

10.10(Exercises) 8.

コード(Xcode)

main.swift

//
//  main.swift
//  sample8
//
//  Created by kamimura on 10/1/14.
//  Copyright (c) 2014 kamimura. All rights reserved.
//

import Foundation

func readMolecule(lines:[String]) -> ([String:[[String]]], [String]){
    if lines.isEmpty {
        return ([:], [])
    }
    var line:String = lines[0]
    var new_lines:[String] = lines.slice(start: 1)
    if line.isEmpty {
        return ([:], new_lines)
    }
    var molecule:[String:[[String]]] = [:]
    var name:String
    if !line.isSpace && !line.startsWith("CMNT") {
        let splited:[String] = line.split(sep: " ")
        name = splited[1].strip
        molecule[name] = []
    } else {
        return (molecule, new_lines)
    }
    var serial_number:Int = 1
    while true {
        line = new_lines[0]
        new_lines = new_lines.slice(start: 1)
        if line.startsWith("END") {
            break
        }
        if !line.isSpace && !line.startsWith("CMNT") {
            let splited:[String] = line.split(sep: " ").map({(s:String) in s.strip})
            let num:Int? = splited[1].toInt()
            if serial_number != num {
                println("\(num!): シリアル番号が\(serial_number)ではない。\(name)")
            }
            let rest:[String] = splited.slice(start: 2)
            if !splited.isEmpty {
                molecule[name]?.append(rest)
            }
        }
        serial_number += 1
    }
    return (molecule, new_lines)
}

func readAllMolecules(lines:[String]) -> [[String:[[String]]]] {
    var result:[[String:[[String]]]] = []
    var new_lines:[String] = lines
    var molecule:[String:[[String]]]
    while true {
        (molecule, new_lines) = readMolecule(new_lines)
        if !molecule.isEmpty {
            result.append(molecule)
        } else {
            break
        }
    }
    return result
}

var lines:[String]? = read(argv[1])?.split(sep: "\n")
if lines != nil {
    let molecules:[[String:[[String]]]] = readAllMolecules(lines!)
    for molecule in molecules {
        println(molecule)
    }
}

stdio.swift

//
//  stdio.swift
//  stdio
//
//  Created by kamimura on 8/21/14.
//  Copyright (c) 2014 kamimura. All rights reserved.
//

import Foundation

// 標準入力(STDIN)から読み込む
func input(msg:String = "") -> String {
    print(msg)
    var in_fh = NSFileHandle.fileHandleWithStandardInput()
    var data = in_fh.availableData
    in_fh.closeFile()
    var s = NSString(data: data, encoding: NSUTF8StringEncoding)
    s = s?.substringToIndex(s!.length - 1)
    return s!
}

func read(path:String) -> String? {
    var fh = NSFileHandle(forReadingAtPath: path)
    let data = fh?.readDataToEndOfFile()
    if fh == nil {
        error("file(\(path)) can't open.")
    }
    fh?.closeFile()
    return NSString(data: data!, encoding: NSUTF8StringEncoding)
}

func print(s:String, path:String, end:String = "\n") {
    (s + end).writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error: nil)
}

func error(msg:String) {
    let stderr = NSFileHandle.fileHandleWithStandardError()
    stderr.writeData((msg + "\n").dataUsingEncoding(NSUTF8StringEncoding)!)
    exit(1)
}

// コマンドライン引数
let argv:[String] = NSProcessInfo.processInfo().arguments.map({(x:AnyObject) -> String in x as String})

string.swift

//
//  string.swift
//  string
//
//  Created by kamimura on 8/10/14.
//  Copyright (c) 2014 kamimura. All rights reserved.
//

import Foundation

extension String {
    var swapcaseString:String {
    var result: String = ""
        for ch in self {
            let s = String(ch)
            result += s.uppercaseString == s ? s.lowercaseString : s.uppercaseString
        }
        return result
    }
    var isUpper:Bool { return self.uppercaseString == self }
    var isLower:Bool { return self.lowercaseString == self }
    var length:Int { return (self as NSString).length }
    var strip:String { return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())}
    var isSpace:Bool { return self.strip == "" }
    var floatValue:Float { return (self as NSString).floatValue }
    var doubleValue:Double { return (self as NSString).doubleValue }
    func count(sub:String) -> Int {
        var result:Int = 0
        var s = self
        let index:String.Index = "a".endIndex
        while s != "" {
            if s.hasPrefix(sub) {
                result += 1
                s = s.substringFromIndex(sub.endIndex)
            } else {
                s = s.substringFromIndex(index)
            }
            
        }
        return result
    }
    func find(sub:String, start:Int = 0, end:Int? = nil) -> Int {
        var s = self as NSString
        var s_temp = s.substringFromIndex(start)
        let end_temp:Int = end != nil ? end! : s.length
        for i in start..<end_temp {
            if (s_temp.hasPrefix(sub)) {
                return i
            }
            s_temp = s.substringFromIndex(i + 1) as NSString
        }
        return -1
    }
    func indexAt(i:Int) -> String {
        if i >= 0 {
            return (self as NSString).substringWithRange(NSRange(location: i, length: 1))
        }
        let new_i = self.length + i
        return (self as NSString).substringWithRange(NSRange(location: new_i, length: 1))
    }
    func replace(old_str:String, new_str:String) -> String {
        return self.stringByReplacingOccurrencesOfString(old_str, withString: new_str)
    }
    func slice(start:Int=0, end:Int?=nil) -> String {
        let s = self as NSString
        var new_end:Int
        if (end != nil) {
            new_end = end!
        } else {
            new_end = s.length
        }
        return  s.substringWithRange(NSRange(location: start, length:new_end - start))
    }
    func split(sep:String = "") -> [String] {
        var result:[String] = []
        if (sep == "") {
            for ch in self {
                result.append(String(ch))
            }
            return result
        }
        var s:String = self
        var len = sep.length
        var temp:String = ""
        while s != "" {
            if s.hasPrefix(sep) {
                if temp != "" {
                    result.append(temp)
                    temp = ""
                }
                s = s.slice(start: len)
            } else {
                temp += s.slice(start: 0, end: 1)
                s = s.slice(start: 1)
            }
        }
        if temp != "" {
            result.append(temp)
        }
        return result
    }
    var reversed:String { return "".join(self.split().reverse()) }
    func repeat(n:Int) -> String {
        var result:String = ""
        for i in 0..<n {
            result += self
        }
        return result
    }
    func startsWith(s:String) -> Bool {
        return s == self.slice(end: s.length)
    }
}

func * (left:String, right:Int) -> String{
    return left.repeat(right)
}

func * (left:Int, right:String) -> String{
    return right.repeat(left)
}

array.swift

//
//  array.swift
//  array
//
//  Created by kamimura on 8/21/14.
//  Copyright (c) 2014 kamimura. All rights reserved.
//

import Foundation

extension Array {
    func indexAt(i:Int) -> T {
        if i >= 0 {
            return self[i]
        }
        let new_index:Int = self.count + i
        return self[new_index]
    }
    func slice(start:Int = 0, end:Int? = nil) -> Array {
        var new_start = start >= 0 ? start : self.count + start
        var new_end:Int
        if end == nil {
            new_end = self.count
        } else if end! >= 0 {
            new_end = end!
        } else {
            new_end = self.count + end!
        }
        var result:Array = []
        if new_start >= new_end {
            return []
        }
        for i in new_start..<new_end {
            result.append(self[i])
        }
        return result
    }
    func forEach(f:(T) -> ()) {
        for e in self {
            f(e)
        }
    }
}

func sum(nums:[Int]) -> Int {
    return nums.reduce(0, combine: {(x, y) in x + y})
}

func range(start:Int = 0, end:Int, step:Int = 1) -> [Int] {
    assert(step != 0, "arg 3 must not be zero")

    var result:[Int] = []
    var elem = start
    
    if step > 0 {
        while elem < end {
            result.append(elem)
            elem += step
        }
    } else {
        while elem > end {
            result.append(elem)
            elem += step
        }
    }
    
    return result
}

入出力結果(Console Output)

$ cat multimol.pdb 
COMPND      AMMONIA
ATOM      1  N  0.257  -0.363   0.000
ATOM      2  H  0.257   0.727   0.000
ATOM      3  H  0.771  -0.727   0.890
ATOM      4  H  0.771  -0.727  -0.890
END
COMPND      METHANOL
ATOM      1  C  -0.748  -0.015   0.024
ATOM      2  O  0.558   0.420  -0.278
ATOM      3  H  -1.293  -0.202  -0.901
ATOM      4  H  -1.263   0.754   0.600
ATOM      5  H  -0.699  -0.934   0.609
ATOM      6  H  0.716   1.404   0.137
END
$ cat multimol1.pdb 
COMPND      AMMONIA
ATOM      1  N  0.257  -0.363   0.000
ATOM      2  H  0.257   0.727   0.000
ATOM      2  H  0.771  -0.727   0.890
ATOM      4  H  0.771  -0.727  -0.890
END
COMPND      METHANOL
ATOM      1  C  -0.748  -0.015   0.024
ATOM      2  O  0.558   0.420  -0.278
ATOM      2  H  -1.293  -0.202  -0.901
ATOM      4  H  -1.263   0.754   0.600
ATOM      4  H  -0.699  -0.934   0.609
ATOM      6  H  0.716   1.404   0.137
END
$ ./sample8 multimol.pdb 
[AMMONIA: [[N, 0.257, -0.363, 0.000], [H, 0.257, 0.727, 0.000], [H, 0.771, -0.727, 0.890], [H, 0.771, -0.727, -0.890]]]
[METHANOL: [[C, -0.748, -0.015, 0.024], [O, 0.558, 0.420, -0.278], [H, -1.293, -0.202, -0.901], [H, -1.263, 0.754, 0.600], [H, -0.699, -0.934, 0.609], [H, 0.716, 1.404, 0.137]]]
$ ./sample8 multimol1.pdb 
2: シリアル番号が3ではない。AMMONIA
2: シリアル番号が3ではない。METHANOL
4: シリアル番号が5ではない。METHANOL
[AMMONIA: [[N, 0.257, -0.363, 0.000], [H, 0.257, 0.727, 0.000], [H, 0.771, -0.727, 0.890], [H, 0.771, -0.727, -0.890]]]
[METHANOL: [[C, -0.748, -0.015, 0.024], [O, 0.558, 0.420, -0.278], [H, -1.293, -0.202, -0.901], [H, -1.263, 0.754, 0.600], [H, -0.699, -0.934, 0.609], [H, 0.716, 1.404, 0.137]]]
$ 

0 コメント:

コメントを投稿