C/C++のフォーマット指定子『%[^\n]』とは？？ その1: 文法編


<sup><font color="silver">1行目からリンクを貼ろうと思いましたが、やっぱやめときます</font></sup>

とあるサイトで見た事が無い記法を発見しました。

``` c:こんな記述
scanf("%[^\n]%*c", c);
```
ほうほう…こうやって書けば…ん？

``` text:君は誰だい？
%[^\n]
```

<b>げっ！何これ！</b>

<font color="silver">(アニメのOP前の映像みたいな演出終了)</font>

#<code>fscanf()</code>で<code>␣</code>(空白文字)も読み込みたい！！
<p>
そう思ってggったんですよ。<br>
そしたらまだ知らなかった方法を2つ発見しました。<br>
<ol>
  <li><code>strtok()</code>を使用する</li>
  <li>フォーマット指定子<code>%[^\n]</code>を使用する</li>
</ol>
…でもね、僕は知らないわけですよ。<code>%[^\n]</code>を。<br>
勿論ggってみました。<br>
<a href="https://www.google.co.jp/search?sxsrf=ALeKk00qddikOwol1uBHx0Sy1YjqNIC5aQ%3A1587700410997&source=hp&ei=umKiXva1OoH6-Qajxqy4Dg&q=%22%25%5B%5E%5Cn%5D%22&oq=&gs_lcp=CgZwc3ktYWIQARgJMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnMgcIIxDqAhAnUABYAGDMHWgDcAB4AIABAIgBAJIBAJgBAKoBB2d3cy13aXqwAQo&sclient=psy-ab" target="_blank">"%[^\n]" - Google 検索</a><br>
残念！この謎の記法についての情報は(10件中)2件しかありませんでした。<br>
<font color="silver">…そういえば、この記事も検索に引っかかんないんですよねぇ。<br>
って事は？これを見っけたあなたは……ラッキーな人？暇人？</font>
</p>


##フォーマット指定子の復習(一応)
<p>
フォーマット指定子といえば<code>%d</code>や<code>%c</code>等があります。<br>
<code>%-4.2f</code><sub></sub>なんて書き方も出来ますね。<br>
<b>あっやっぱ知らない人や思い出せない人は、自分で調べて下さい。</b>
</p>


#取り敢えず実際に使ってみる

<code>※環境は Win10Pro<sub>(CORE i7 8th Gen + UHD620)</sub> + VS2017<sub>(2020年4月時点で最新)</sub></code>
先ずは普通に標準入力から読み込みをしてみましょう。

``` c:main.c
#pragma warning(disable:4996)
#include <stdio.h>
#include <Windows.h> //system() を使用する為

int main(void) {
	char str[64] = { '\0' };
	scanf("%s", str); //読み込み
	printf("str = \"%s\"\n", str); //出力
	system("pause");
}
```
``` result:実行結果
Ashole is anus
str = "Ashole"
続行するには何かキーを押してください . . .
```
<sup>※以降はプリプロセッサ命令を省略します</sup>
ああ。無情。皆さんご存知の通り、空白文字が区切りになって、"is"以降が読み込まれません…。
では早速、あの秘密兵器を使ってみましょう。

``` c:%[^\n]を使用したmain.c
int main(void) {
	char str[64] = { '\0' };
	scanf("%[^\n]%s", str); //読み込み
	printf("str = \"%s\"\n", str); //出力
	system("pause");
}
```
``` result:実行結果
Ashole is Anus
nanigaokottanoda
(!!メモリ書き込みアクセス違反!!)
```
<sup>※以降はscanf以外も省略します</sup>
あれ？うまくいきませんでした。2回改行した時点で<i>メモリアクセス違反</i>で落ちました。
<br>

``` c:%sを消したmain.c
	scanf("%[^\n]", str); //読み込み
```
``` result:実行結果
Anus is Anus
str = "Anus is Anus"
続行するには何かキーを押してください . . .
```
今度は上手くいきました。改行文字<code>\n</code>まで読み込まれています。

``` c:%[^\n]sにしたmain.c
	scanf("%[^\n]s", str); //読み込み
```
これでも上手くいきました。
<br>

``` c:%[^\ns]にしたmain.c
	scanf("%[^\ns]", str); //読み込み
```
``` result:実行結果
Anus is My father
str = "Anu"
続行するには何かキーを押してください . . .
```
しかし、<code>s</code>を四角括弧<code>[ ]</code>の中に押し込んだら、1つ目の<code>s</code>の直前迄しか読み込まれませんでした。
<b>まるで<code>s</code>が区切り文字になったみたいですね。</b>
<br>
……もう勘の良い人なら何かに気付いたと思います。

そうだネ<sub>(魚を捌くサイコパス系動画投稿者)</sub>
#%[^ ... ]内に記述された文字が区切り文字になる

<font color="silver">(この解釈で合っていると思います。)</font>
なので、

``` c:%[^\n]を使用したmain.c
	scanf("%[^\n]%s", str); //読み込み
```
<p>
と記述すれば
<ol>
  <li>設定されている<code>\n</code>まで読み込む</li>
  <li>区切り文字まで読み込む</li>
</ol>
と、文字配列が<b>2回</b>読み込まれたので、メモリ書き込みアクセス違反が起こっていたって訳ですね！<br>
<font color="silver">
いや基本を押さえてれば誰でも分かるわ！
</font><br>
そして、
</p>

``` c:%[^\ns]にしたmain.c
	scanf("%[^\ns]", str); //読み込み
```
これで<code>s</code>が区切り文字の様に振る舞っていたのは、<b>本当に区切り文字になっていたから</b>だったのです！


###他の文字で試してみる
<code>^</code>を区切り文字にする場合は、

``` c:'^'を区切り文字にするぜ！なmain.c
	scanf("%[^^]", str); //読み込み
```
``` result:実行結果
Anus aaagghhhhhhhhh!!!!
anus!anus
aaaa!!^
str = "Anus aaagghhhhhhhhh!!!!
anus!anus
aaaa!!"
続行するには何かキーを押してください . . .
```
こういう風に記述します。なんと！改行文字も読み込まれました。

<hr>


<a href="https://qiita.com/Sankyuri/items/10b1ab4aac35751602cd" target="_blank"><code><b><font color="red">これ</font></b></code></a>へ続く…
(<b>こんなの使わねぇ！</b>って人と、只々これを使えるようになるだけで満足なおチビちゃんは、次以降は読まなくても大丈夫だと思います。)

#参考…？

<a href="https://qiita.com/sea_ship/items/7c8811b5cf37d700adc4#%E6%96%87%E5%AD%97%E3%82%AF%E3%83%A9%E3%82%B9" target="_blank"><code><b><font color="red">こちら</font></b></code></a>は Java の正規表現:文字クラスです。見ると分かりますが、似てますよね。
なんと、確認したら<code>[abc]</code>, <code>[^abc]</code>, <code>[a-z]<font color="red"><sub>(※環境依存)<sub></font></code>は動作しました。(それ以外は仕様に無い様です)。












<br><br><br><br><br><br><br>