文字の範囲・文字列の範囲

Crystalの文字列の範囲の挙動が気になったので、他の言語でどうなっているかいろいろ調べた.

## Perl

```
% perl -v | head -2 | tail -1
This is perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux
```

* 文字 `Z` の次の文字

```
% perl -e 'print chr ++($foo = ord "Z");'
[
```

* 文字列 `Z` の次の文字列

```
% perl -e 'print ++($foo = "Z");'
AA
```

* 文字列の範囲

```
% perl -e 'print "A".."Z";'
ABCDEFGHIJKLMNOPQRSTUVWXYZ
```

```
% perl -e 'print "A".."z";'
ABCDEFGHIJKLMNOPQRSTUVWXYZ
```

これは強烈.

```
% perl -e 'print "a".."Z";'
abcdefghijklmnopqrstuvwxyz
```

```
% perl -e 'print "ZZ".."z";'
%
```

## Ruby

```
$ ruby -v
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin13]
```

* 文字 `Z` の次の文字

```rb
> "Z".ord.succ.chr
=> "["
```

* 文字列 `Z` の次の文字

```rb
> "Z".succ
=> "AA"
```

* 文字列の範囲

```rb
("A".."z").to_a
=> ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
```

```rb
> ("A".."AA").to_a
=> ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA"]
```

```rb
> ("ZZ".."z").to_a
=> ["ZZ"]
```

## Python

```
$ python -V
Python 3.4.2
```

* 文字 `Z` の次の文字

```py3
In [1]: x = ord("Z"); x += 1; chr(x)
Out[1]: '['
```

* 次の文字列を表す

できない.

* 文字の範囲

それっぽい構文はないが、書けなくはない.

```py3
for x in range(ord("A"), ord("[")):
    print(chr(x), end="")
#=> ABCDEFGHIJKLMNOPQRSTUVWXYZ
```

`import string` すると `string.ascii_letters` を使うこともできるがアルファベットの大文字小文字のみ.

```py3
for x in string.ascii_letters:
    print(x, end="")
#=> abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
```

* 文字列の範囲

できない.

## D言語

```
% dmd -v | head -1
DMD64 D Compiler v2.068.0
```

* 文字 `Z` の次の文字

```d
import std.stdio;

void main()
{
  char x;
  (++(x = 'Z')).writeln;
}
```

```
% rdmd x.d
[
```

* 文字列 `Z` の次の文字列

```d
import std.stdio;
import std.string;

void main()
{
  "Z".succ.writeln;
}
```

```
% rdmd xx.d
AA
```

* 文字の範囲

```d
import std.stdio;
import std.range;

void main()
{
  iota('A', '[').writeln;
}
```

```
% rdmd xxx.d
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
```

* 文字列の範囲

できない.

## Crystal

```
% crystal -v
Crystal 0.7.7 [170f859] (Sat Sep  5 02:53:51 UTC 2015)
```

* `Z` の次の文字

```crystal
puts 'Z'.succ
```

```
% crystal x.cr
[
```

* `Z` の次の文字列

```crystal
puts "Z".succ
```

```
% crystal x.cr
AA
```

* 文字の範囲

```crystal
% cat xx.cr
p ('A'..'z').to_a
```

```
% crystal xx.cr
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
```

* 文字列の範囲

これは問題ない.

```Crystal
% cat xxx.cr
p ("A".."Z").to_a
```

```
% crystal xxx.cr
["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
```

問題のケース.

```crystal
% cat xxx.cr
p ("A".."z").to_a
```

"A" -> "Z" -> "AA" -> "ZZ" -> "AAA" -> "AAA.." -> "ZZZ.." が無限に呼ばれる.

```
% crystal xxx.cr
^C
```

# 総評

文字列の範囲の実装はけっこう違いがある. ここにはのせなかったけれど、JuliaやElixirなんかは文字列の範囲や `String#succ` 相当のものを実装していないみたい.