fluorite-7　日本語チュートリアル　Part 7　標準入力と文字列操作


[チュートリアルトップ](https://qiita.com/MirrgieRiana/items/a0906c72ebfb46693ab5)

[←前回](https://qiita.com/MirrgieRiana/items/ac7d866e71c61fb9b004)　[次回→](https://qiita.com/MirrgieRiana/items/d4af50233a37e5d84646)

このパートでは、標準入力と簡単な文字列の加工について取り扱います。

# レッスン1　標準入力

コンソール版fluorite-7では、組み込み定数`IN`に標準入力を1行ずつ読み出すストリーマが格納されています。

```bash:
$ echo -e 'abc\ndef' | fl7 'IN'
abc
def
```

`IN`はストリーマであるため、パイプでそのまま1行ごとにデータを処理できます。

```bash:
$ echo -e 'abc\ndef' | fl7 'IN | [_, _]'
abc,abc
def,def
```

# レッスン2　文字列長

長さ演算子`$#`で文字列の長さが得られます。

```bash:
$ fl7 '$#"abcdefg", $#"あ"'
7
1
```

全角文字も1文字としてカウントされますが、サロゲートペアは2文字としてカウントされます。

----

標準入力の1行ごとに処理ができるようになって、文字列長の取得という計算が可能になったので、何か処理を行ってみましょう。

`cat /etc/nanorc | grep -vE '^#|^$'`というbashコマンドでは以下のような出力が得られました（環境によります）。

```bash:
$ cat /etc/nanorc | grep -vE '^#|^$'
set historylog
set locking
set nowrap
set suspend
include "/usr/share/nano/*.nanorc"
```

これに`fl7 'IN | $#_'`をくっつけてみましょう。

```bash:
$ cat /etc/nanorc | grep -vE '^#|^$' | fl7 'IN | $#_'
14
11
10
11
34
```

`set nowrap`が`10`に変換されました。
改行を含んでいない文字が`_`にやってきているのが分かります。

# レッスン3　位置アクセス

「文字列`[`位置`]`」で、特定の位置にある文字を取り出します。
これをfluorite-7では**位置アクセス**と呼びます。

```bash:
$ fl7 '"abcdefg"[4]'
e
```

負の位置を指定した場合、文字列の末尾から数えた位置の文字を取得します。
-1であれば最後の文字が得られます。

```bash:
$ fl7 '"abcdefg"[-1]'
g

$ fl7 '"abcdefg"[-7]'
a
```

# レッスン4　部分アクセス

「文字列`[`開始位置`;`終了位置`]`」で文字列の特定の一部分を切り出すことができます。
これをfluorite-7では**部分アクセス**と呼びます。
切り出される文字は、終了位置にある文字を含みません。
得られる文字列の長さは(終了位置-開始位置)になります。

```bash:
$ fl7 '"abcdefg"[2; 5]'
cde
```

終了位置は省略できます。
終了位置を省略すると、文字列の末尾までを切り出します。

```bash:
$ fl7 '"abcdefg"[2; ]'
cdefg
```

開始位置を省略すると、文字列の先頭からになります。

```bash:
$ fl7 '"abcdefg"[; 5]'
abcde
```

両方省略したらどうなるでしょうか。

```bash:
$ fl7 '"abcdefg"[; ]'
abcdefg
```

両方省略すると、文字列の先頭から末尾までを切り出します。
fluorite-7の文字列は不変オブジェクトなので、これをやる意味は特にないです。

----

こちらも負の位置指定ができます。

```bash:
$ fl7 '"abcdefg"[-4; -1]'
def
```

これは末尾から4文字から、末尾から1文字目の手前までを抜き出します。

## Tips　配列の切り出し

実は全く同じ指定の仕方が配列でもできます。

```bash:
$ fl7 '[zero, one, two, three][2]'
two

$ fl7 '[zero, one, two, three][-1]'
three

$ fl7 '[zero, one, two, three][1; 3]'
one,two

$ fl7 '[zero, one, two, three][1; ]'
one,two,three

$ fl7 '[zero, one, two, three][; 3]'
zero,one,two

$ fl7 '[zero, one, two, three][; ]'
zero,one,two,three

$ fl7 '[zero, one, two, three][-3; -1]'
one,two
```

# レッスン5　文字列のストリーマ展開

文字列に対して後置`[]`を置くと、文字のストリーマを得ます。

```bash:
$ fl7 '"abcde"[]'
a
b
c
d
e
```

1文字ごとに処理を行うことができます。

```bash:
$ fl7 '"abcde"[] | "[$(_)]"'
[a]
[b]
[c]
[d]
[e]
```

# レッスン6　文字列結合

中置`&`は、左右の値を文字列として認識し、結合します。

```bash:
$ fl7 '"Score: " & 400'
Score: 400
```

これは埋め込みと似ています。

```bash:
$ fl7 '"Score: $(400)"'
Score: 400
```

# レッスン7　文字列の繰り返し

中置`*`を文字列に対して行うと、その文字列を繰り返します。

```bash:
$ fl7 '"abc" * 3'
abcabcabc
```

# レッスン8　文字列化・数値化

前置`&`は値の文字列化、前置`+`は値の数値化を行います。

```bash:
$ fl7 '&400, +"400"'
400
400
```

これだけでは分からないので、値の型を見てみましょう。

```bash:
$ fl7 'TYPE(400), TYPE("400")'
NUMBER
STRING

$ fl7 'TYPE(&400), TYPE(+"400")'
STRING
NUMBER
```

`&400`は`STRING`、`+"400"`は`NUMBER`となりました。
データの変換が行われていることが分かります。

----

文字列の数値化は、文字列として格納されている数値を使用して算術を行う際に必須です。
例えば次のコードはどうなるでしょうか。

```bash:
$ fl7 '"999" + 1'
```

このような「文字列として格納された数値」と数値の足し算の挙動は、プログラミング言語によってまちまちです。
fluorite-7では、中置`+`演算子は、左辺が文字列であれば文字列結合を行います。

```bash:
$ fl7 '"999" + 1'
9991
```

この場合、999と1を足した1000を得るには、左辺を明示的に数値化します。

```bash:
$ fl7 '+"999" + 1'
1000
```

他にも、数値同士を並べた数値を作るときに文字列の数値化が使えます。

```bash:
$ fl7 '+(5 & 4 & 3) + 10000'
10543
```

`5 & 4 & 3`はこのままでは文字列なので`+ 10000`をすると`54310000`という文字列になってしまいますが、`5 & 4 & 3`に`+`を付けることで543という数値を得て、それに10000を加算したので10543という数値が得られました。

# レッスン9　JOIN関数・SPLIT関数

組み込み定数`JOIN`には、ストリーマの各要素を文字列化し、`,`で結合する関数が入っています。

```bash:
$ fl7 'JOIN(1 .. 4)'
1,2,3,4
```

これだけでは配列の文字列化と変わりありません。

```bash:
$ fl7 '&[1 .. 4]'
1,2,3,4
```

しかし、JOIN関数は第2引数に結合に使う文字列を受け取れます。

```bash:
$ fl7 'JOIN(1 .. 4; " / ")'
1 / 2 / 3 / 4
```

----

SPLIT関数はJOIN関数とは逆に、1個の文字列を`,`で分割し、ストリーマにします。

```bash:
$ fl7 'SPLIT("1,2,3,4")'
1
2
3
4
```

SPLIT関数も同様に第2引数で分割文字列を受け取れます。

```bash:
$ fl7 'SPLIT("1 / 2 / 3 / 4"; " / ")'
1
2
3
4
```

# レッスン10　標準入力からのカラムの選択

前の方で出たこのコマンド出力の、`historylog`や`"/usr/share/nano/*.nanorc"`の部分を取り出してみましょう。

```bash:
$ cat /etc/nanorc | grep -vE '^#|^$'
set historylog
set locking
set nowrap
set suspend
include "/usr/share/nano/*.nanorc"
```

つまり、このような文字列の出力を目指します。

```
historylog
locking
nowrap
suspend
"/usr/share/nano/*.nanorc"
```

----

まず`IN`だけを置くと、入力したものを何もせずそのまま出力します。
各行に対して処理を行いたいので`IN`にパイプを付けて行ごとに加工できるようにします。

```bash:
$ cat /etc/nanorc | grep -vE '^#|^$' | fl7 'IN | _'
set historylog
set locking
set nowrap
set suspend
include "/usr/share/nano/*.nanorc"
```

`_`は恒等変換なので、このままでは入力したものをそのまま出力するだけです。

各行に対して空白で分割したいので、各行に対して`SPLIT(_; " ")`を適用します。
SPLIT関数はストリーマを返すので、`[` `]`で囲んで一旦配列にします。

```bash:
$ cat /etc/nanorc | grep -vE '^#|^$' | fl7 'IN | [SPLIT(_; " ")]'
set,historylog
set,locking
set,nowrap
set,suspend
include,"/usr/share/nano/*.nanorc"
```

区切りが`,`になりました。あとは添え字1の要素を取得すれば完成です。

```bash:
$ cat /etc/nanorc | grep -vE '^#|^$' | fl7 'IN | [SPLIT(_; " ")][1]'
historylog
locking
nowrap
suspend
"/usr/share/nano/*.nanorc"
```

# まとめ

- `IN`で標準入力を1行ずつ読み込む。
- `$#string`で文字列長が得られる。
- `string[index]`で文字が得られる。
- 負の位置を指定すると末尾から数える。
- `string[start; end]`で部分文字列が得られる。
- 部分文字列の開始・終了位置は省略できる。
- `string[]`で文字のストリーマを得る。
- `value1 & value2`は文字列として結合する。
- `string * number`で文字列を繰り返す。
- `&value`で文字列化、`+value`で数値化する。
- `JOIN`でストリーマを特定の文字列で結合できる。
- `SPLIT`で文字列を特定の文字列で分割してストリーマにできる。

# Part 8

[次回→](https://qiita.com/MirrgieRiana/items/d4af50233a37e5d84646)