ソースコードで想いを届ける（Swift コマンドライン編）

[ソースコードで想いを届ける](http://qiita.com/UltraBirdTech/items/e06c36b36b609a090484)という記事を読んだら、「ああなるほど恋人ができないのはそもそも思いを届けてないからだね、ちゃんと自分の思いをあの娘に伝えてあげなきゃ」と思ったわけです
※たぶん、そういうことじゃない。

でもまあせっかく Swift のコードも書いていただいたのですが Playground だけじゃあつまらないからコマンドラインでも弄ってみたいと思いますので、エディタ開いてこんなコード書いてみます：

```swift:iLoveYou.swift
import Foundation

if Process.arguments.count > 1 {
	let name = Process.arguments[1]
	print("私は\(name)のことが好きです")
	
} else {
	print("私は好きな人がいません")
}
```

これで `Process.arguments` でコマンドラインで入力した引数を受け取って好きな人の名前として告白します。使う時はターミナル開いて下記のように使います

```bash
% swift iLoveYou.swift 春彦母
私は春彦母のことが好きです
```

※「春彦母」は「無彩限のファントム・ワールド」に出てきた主人公一条春彦の母親のことです。名前は設定されてないようです。
※マザコンではありません。たまたま好きなキャラクターが人の母親なだけです(ry

ところで、まあ日本語だったらこれで問題ないのですが、好きな人が外国人とかの場合英語で名前入れたい場合もあると思いますが、英語だと途中でスペースが入るから引数として分割されちゃうから面倒いよな。というわけでちょっとカスタマイズ：

```swift:iLoveYou.swift
import Foundation

if Process.arguments.count > 1 {
	//let name = Process.arguments[1]
	let name = Process.arguments.dropFirst().reduce("", combine: {$0.isEmpty ? $1 : $0 + " " + $1})
	print("私は\(name)のことが好きです")
	
} else {
	print("私は好きな人がいません")
}
```

これで bash にスペースを入れても問題ない：

```bash
$ swift iLoveYou.swift Haruhiko Mom
私はHaruhiko Momのことが好きです
```

さて、ここでもう一つこだわりを入れてみます。きちんとした UI デザインとかやられた方ならわかると思いますが、実は普通はですね、英数字と漢字の間に、半角スペースを一つ空ける習慣があるのです（正確には半角文字と全角文字の間には半角スペースを入れる必要があります）。「ん？」って思われる方は今ご覧のブラウザのメニューとかを覗いてみてください。Mac の Safari ならこんな感じです：
<img width="166" alt="スクリーンショット 2016-04-04 14.38.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/63998/46bcb0bc-ce66-b147-0365-d13413589b90.png">
まあ Windows はもともとフォントが汚かったりと割とここら辺のこだわりはアップルと比べると薄いのですが、それでも一応ちゃんと半角スペースを空けてます：
<img width="298" alt="スクリーンショット 2016-04-04 14.37.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/63998/e579da0a-539b-ddcd-64a5-e17b91b8ef97.png">
と、このように、半角スペースを一つ入れたことで見た目がだいぶ綺麗になりますよね。というわけで一応ちゃんとした綺麗な告白テキストを作るには、先頭と末尾の文字が英数字かどうかを判別して必要に応じて半角スペースを入れる必要があるんじゃないかと個人的に思います。というわけで大改造します。

```swift:iLoveYou.swift
import Foundation

extension NSCharacterSet {
	
	class func alphabetAndNumberCharacterSet() -> NSCharacterSet {
		let set = NSCharacterSet(charactersInString: "ABCDEFGHIJKLMNOPQRSTUVWXYZÅØÁÉÍÓÚÂÊÎÔÛÀÈÌÒÙÄËÏÖÜÃÕabcdefghijklmnopqrstuvwxyzåøáéíóúâêîôûàèìòùäëïöüãõß0123456789")
		return set
	}
	
}

extension String {
	
	var startsWithAlphanumericCharacter: Bool {
		guard self.characters.count > 0 else {
			return false
		}
		
		let firstCharacter = self.substringToIndex(self.startIndex.successor())
		if firstCharacter.rangeOfCharacterFromSet(.alphabetAndNumberCharacterSet()) == nil {
			return false
			
		} else {
			return true
		}
		
	}
	
	var endsWithAlphanumericCharacter: Bool {
		guard self.characters.count > 0 else {
			return false
		}
		
		let firstCharacter = self.substringFromIndex(self.endIndex.predecessor())
		if firstCharacter.rangeOfCharacterFromSet(.alphabetAndNumberCharacterSet()) == nil {
			return false
			
		} else {
			return true
		}
	}
}

if Process.arguments.count > 1 {
	let name = Process.arguments.dropFirst().reduce("", combine: {$0.isEmpty ? $1 : $0 + " " + $1})
	let prefix = name.startsWithAlphanumericCharacter ? " " : ""
	let suffix = name.endsWithAlphanumericCharacter ? " " : ""
	let output = prefix + name + suffix
	print("私は\(output)のことが好きです")
	
} else {
	print("私は好きな人がいません")
}
```

```bash
$ swift iLoveYou.swift 春彦母
私は春彦母のことが好きです
$ swift iLoveYou.swift Haruhiko Mom
私は Haruhiko Mom のことが好きです
```

まあとりあえず自分がわかってるアルファベットの文字を全部入れといたけどロシア語とかの場合は判別できないんだよな。仕方ない。というか何故 NSCharacterSet にあらかじめこんなセットを作ってくれなかったし。

***
追伸：ところでよく考えてみたらそもそもこのプログラムを走らしてるってことはつまり好きな人に告白したいってわけだから名前入力しないとおかしいよな。というわけで `if` より `guard else` 使った方が良さそうな希ガス。

```swift:iLoveYou.swift
import Foundation

extension NSCharacterSet {
	
	class func alphabetAndNumberCharacterSet() -> NSCharacterSet {
		let set = NSCharacterSet(charactersInString: "ABCDEFGHIJKLMNOPQRSTUVWXYZÅØÁÉÍÓÚÂÊÎÔÛÀÈÌÒÙÄËÏÖÜÃÕabcdefghijklmnopqrstuvwxyzåøáéíóúâêîôûàèìòùäëïöüãõß0123456789")
		return set
	}
	
}

extension String {
	
	var startsWithAlphanumericCharacter: Bool {
		guard self.characters.count > 0 else {
			return false
		}
		
		let firstCharacter = self.substringToIndex(self.startIndex.successor())
		if firstCharacter.rangeOfCharacterFromSet(.alphabetAndNumberCharacterSet()) == nil {
			return false
			
		} else {
			return true
		}
		
	}
	
	var endsWithAlphanumericCharacter: Bool {
		guard self.characters.count > 0 else {
			return false
		}
		
		let firstCharacter = self.substringFromIndex(self.endIndex.predecessor())
		if firstCharacter.rangeOfCharacterFromSet(.alphabetAndNumberCharacterSet()) == nil {
			return false
			
		} else {
			return true
		}
	}
}

func run() {
	
	guard Process.arguments.count > 1 else {
		print("ファイル名の後に名前を入力してください。例：$ swift example.swift HER NAME")
		return
	}
	
	let name = Process.arguments.dropFirst().reduce("", combine: {$0.isEmpty ? $1 : $0 + " " + $1})
	let prefix = name.startsWithAlphanumericCharacter ? " " : ""
	let suffix = name.endsWithAlphanumericCharacter ? " " : ""
	let output = prefix + name + suffix
	print("私は\(output)のことが好きです")
	
}

run()
```