C言語で電卓を作ろう

C言語で簡単な数式を読んで計算するプログラムを作ります。

数式内で使える演算子は「+」「-」「*」の3つで、括弧は使えません。

使える数は0以上の整数で、負の数は使えません。

 

優先順位は「*」が高く、「+」と「-」が低くなるようにします。「2 + 3 * 4」は 20 ではなく 14 になります。

 

3つの変数 a、b、c を用意し、a と c を 0、b を 1 で初期化しておきます。

受け取った数式を最初から順番に読んでいって、「*」があったら b に a をかけ、「+」「-」があったら c に a * b を足します。これらの演算子を読んだ後、a に 0 を代入し、bに「+」なら 1、「-」なら -1 を代入します。数字を読み込んだ場合は a に 10 をかけて足します。

 

これを文字列の終わりまで繰り返したら、a * b + c が計算の答えです。

 

コードはこちら

github.com

 

+と-と*しか無いからこそ実現できるシンプルさです。

でも変数を1つ増やせば「/」も追加できないことはなさそう。

ただ、括弧を使いたいときにこのやり方は使えないので他のやり方を考える必要があります。

X

Arch LinuxGUI環境を構築した。GUI環境は欲しい時にだけ使いたくて、普段の作業はコンソールでやるつもりだったので、startxコマンドでXを起動→$mod+EでXを終了ができるようにした。ウィンドウマネージャはi3を選んだ。

 

xorg-server, xorg-apps, xorg-xinitをインストール。この時点でstartxとするとXが立ち上がり、即座に終了する。

 

i3, dmenu, xtermをインストール。さらにフォントを扱うfontconfig, xorg-font-utils も必要だが、これはXフォントを何か1つインストールすると手に入る(公式リポジトリにある otf-ipafont など)。

 

/etc/X11/xinit/xinitircを~にコピーして編集する。最後のtwmとかxclockとかxtermとかの行は向こうが勝手に走らせているだけなので消す(そもそもtwmとxclockはインストールしてない)。そしてexec i3と書き加える。

 

この状態でstartxとするとi3が起動する。言われるがままにmodキーなどを設定する。$mod+Enterでxtermを起動する。psでi3を探して殺し、コンソール環境に戻る。すると/.config/i3にconfigという設定ファイルが作られているので、これを編集して$mod+Shift+eのショートカットが書かれた行を bindsym $mod+Shift+e exit と書き換える。この状態でstartxとすると$mod+Shift+eで即座にXが閉じるようになっている。

 

キーボードレイアウトは/etc/X11/xorg.conf.dにファイルを作って指定する。00-keyboard.confの1つだけを書いた。

Section "InpurClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XKbLayout" "us"
Option "XKbVariant" "dvp"
EndSection

 

設定は完了した。firefoxをインストールして挙動を確認したりする。あと僕は/.config/i3/configの最後にbindsym $mod+Escape exec i3lock -c000000と書き加えて、即座に画面ロックができるようにしたりした。

Arch Linux インストールの流れ

BIOS/MBRUEFI/GPTのうち、より優れたUEFI/GPTを使う。

 

全体の流れ

1. インストール作業のための一時的な設定

2. パーティション分け

3. Linux自体のインストール

(chroot)

 4. 今後使う上で必要な設定

 5. 次回起動時のブートローダのインストールと設定

 6. 再起動

 7. 諸設定

 

Arch Linuxのインストールメディアは牛肉屋を営む牛のようなものである。牛が仕入れて客に提供するのは牛肉だが、牛が自らを捌いて売るわけではない。同様に、Arch Linuxのインストールメディアはインターネット上からArch Linuxをダウンロードしてコンピュータにインストールするが、インストールメディアの中のArch Linuxがコピーされるわけではない。また、ユーザーは初めのうちは売る方の牛に指示を出すが、途中からは売られた方の牛を調理するようになる。この切り替えがchrootである。

インストール作業の中でテキストエディタviが登場する。慣れないうちは操作が大変なのでnanoを代わりに使ってもよい。ただ今後のためにviを使うことを推奨する。

 

以上のことを押さえた上でインストール作業に取り掛かる。

 

インストールメディアの入ったUSBメモリーを刺し、有線でインターネットに繋ぎ、PCの電源ボタンを押して即座にF2、Boot List Optionで[UEFI]、Boot Option #1で[UEFI: (USBメモリの名前)]を選択、Save Changes and Reset。表示される選択肢の中からArch Linux archiso x86_64 UEFI USBを選択して起動、Welcome to Arch Linux! に続いてコンソールに文字が流れる。

 

tty1でroot自動ログインが行われ、入力を受け付ける状態になる。

archiso login: root (automatic login)

root@archiso ~ # _

 

1. インストール作業のための一時的な設定

Dvorakユーザなのでloadkeysを使って切り替える。

loadkeys dvorak-programmer.map

 

pingを使ってインターネット接続を一応確認する。

ping -c3 www.google.com

 2. パーティション分け

ディスク/dev/sdaのパーティションを決める。UEFIなのでgdiskまたはcgdiskを使う。僕はどちらかというと対話型のgdiskの方が使いやすいように感じた。/dev/sdaはコマンドライン引数と標準入力のどちらでも指定できる。

gdisk /dev/sda

コマンド入力を受け付けるようになる。

oで新しいパーティションテーブルを作成し、ここにパーティションを書いてゆく。

Command (? for help): o

This option deletes all partitions and creates a new protective MBR.

Proceed? (Y/N): Y

UEFIの場合まず/boot用のEFI System パーティション(ESP)を作る必要がある。Hex CodeとしてEF00を指定することでLinux filesystemではなくEFI systemとし、512M用意する。デフォルトのままのところは何も打たずにエンターを押せば良い。

Command (? for help): n

Partition number (1-128, default 1):

First sector () or {+-}size{KMGTP}:

Last sector () or {+-}size{KMGTP}: +512M

Current type is 'Linux filesystem'

Hex code or GUID (L to show codes, Enter = 8300): EF00

Changed type of partition to 'EFI System'

残りはすべて/用のrootパーティションとした。ここで/homeを分けてしまうと後でブートローダがエラーを吐く(指定の仕方を間違えたのだろうか)。

Command (? for help): n

Partition number (1-128, default 2):

First sector () or {+-}size{KMGTP}:

Last sector () or {+-}size{KMGTP}:

Current type is 'Linux filesystem'

Hex code or GUID (L to show codes, Enter = 8300):

Changed type of partition to 'Linux filesystem'

メモリが1GB以下だとswapも作ることが多いが、幸い4GB(十分!)もあったので作らなかった。swapを作るとしたらHex codeは8200になる。

そしてwriteで作成したパーティションテーブルをハードディスクに書き込む。

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!!

Do you want to proceed? (Y/N): Y

これで/dev/sda1(後の/boot)、/dev/sda2(後の/)の2つのパーティションが作られた。

 

ESPはF32でフォーマットする。

mkfs.vfat -F32 /dev/sda1

他はext4でフォーマットする。

mkfs.ext4 /dev/sda2

swapを作るならここでmkswap /dev/sdaXとswapon /dev/sdaXを行う。 

/dev/sda2(後の/)を/mnt自体にマウントする。

mount /dev/sda2 /mnt

 /dev/sda1(後の/boot)は/mnt/bootを作ってマウントする。

mkdir /mnt/boot

mount /dev/sda1 /mnt/boot

 3. Linux自体のインストール

viを起動してミラーリスト(どのサーバーから優先的に落とすか)を設定する。

vi /etc/pacman.d/mirrorlist

日本在住の場合Japanを検索して一番上に持ってくる。キーボード操作としては「/Japan(エンター)」で検索、「2dd{p」でコピー&ペースト、「n」と「N」で次を検索&前を検索、終わったら「:wq(エンター)」で保存&終了。

 

pacstrapでLinuxをインストールする。

pacstrap -i /mnt base base-devel

エンターを押し続け、言われたものを全てインストールする。

 

fstabを生成する。

genfstab /mnt >> /mnt/etc/fstab

次回起動時に/mntが/、/mnt/bootが/bootになる。ここでfstabが書き込まれた/mnt/etc/fstabを確認する(cat /mnt/etc/fstab)と、/dev/sda2がext4で/に、/dev/sda1がvfatで/bootになるという趣旨の表があるはずだ。genfstabに-Uオプションを付けていると左の列がUUID=(数字とアルファベットの羅列)になる。

 

肉屋で牛肉を買い終えた。このあとは肉屋を出て、受け取った牛を調理する。

arch-chroot /mnt

家に帰って牛肉を調理台に置いた。

 4. 今後使う上で必要な設定

viで/etc/locale.genを開く。

vi /etc/locale.gen

 「/en_US」などとして「n」「N」を使いながら「# en_US.UTF-8 UTF-8」と書かれた行を探し、「0x」でコメントアウト。同様に「/ja_JP」などとして「# en_US.UTF-8 UTF-8」を探し、「0x」でコメントアウト。「:wq」で保存終了。そして変更を反映。

locale-gen

 

locale.confで言語を設定する。

echo LANG=en_US.UTF-8 > /etc/locale.conf
export LANG=en_US.UTF-8

 

次回起動時のキーボードレイアウトとフォントを設定する。

vi /etc/vconsole.conf

 「i」で入力を開始、Escで入力を終了。

KEYMAP=dvorak-programmer.map
FONT=Lat2-Terminus16

とした。

 

場所の設定。

ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

時刻の設定。

 hwclock -u -w

ホスト名の設定。

echo (ホスト名) > /etc/hostname

 

インターネット接続にはdhcpcdを使う。systemctlコマンドを使い、起動時にdhcpcdが自動でインターネットに接続するようにする。systemctlの後に続けてオプションを指定する:その場で立ち上げるにはstart、その場で止めるにはstopを使い、enable↔disableは起動したときに立ち上がるかどうかを選ぶ。次回起動時に繋がらなかった場合はまたsystemctlを使ってdhcpcdの状態を確認する。

systemctl enable dhcpcd

 

パスワードを設定する。

passwd

 5. 次回起動時のブートローダのインストールと設定

Arch Linux自体の設定は完了した。現在Arch Linuxは起動した状態であり、ここからこのOSをずっと起動したままで使い続けることが可能である。いわば暖炉の中で薪が燃えている状態である。あなたはその火を使ってさまざまなことができる。

しかしあなたはまだマッチを持っていない。今燃えている火は、USBメモリのarchisoが点火してくれた火である。暖炉と薪は整ったが、マッチが無いことには火を付けることができない。

マッチとなるのはブートローダである。ブートローダには数種類あるが、今回はsystemd-boot(旧称gummiboot)を使う。インストール。

bootctl --path=/boot install

この後いくつかの設定を行い、USBを抜いて再起動する。設定に失敗すると次の再起動ができなくなる。その場合は慌てずUSBを挿し直して起動し、/dev/sda1と/dev/sda2のマウントを上と同じように行い、ここからやり直す。

 設定するのは/boot/loader/entriesディレクトリと/boot/loader/loader.confファイルの2つである。

まず/boot/loader/entriesに移動する。

cd /boot/loader/entries

/boot/loader/entriesには起動モードの選択肢1つごとに1つのファイルを拡張子confで作る。arch.conf(普段)とarch-fallback.conf(Fallback、何かあったとき用)の2つを用意する。

ルートパーティション/dev/sda2の固有PARTUUIDを調べる。

blkid -s PARTUUID -o value /dev/sda2

arch.confを編集して次のようにする。

title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=PARTUUID=(PARTUUID) rw

PARTUUIDのところにblkidで調べたPARTUUIDを書く。長い文字列なので、メモするのが面倒ならblkidの最後に> arch.confと付け加えておくとPARTUUIDが表示される代わりにarch.confに出力される。

arch-fallback.confは

title Arch Linux Fallback
linux /vmlinuz-linux
initrd /initramfs-linux-fallback.img
options root=PARTUUID=(PARTUUID) rw

次に、既に存在する/boot/loader/loader.confを編集する。

cd ..

vi loader.conf

このファイルに一行ずつ設定を書いていく。必ず書かなければならないのは「editor no」の一行である。これを書かないと、「スペースキーを押しながら起動→eを押してinit=/bin/bashを書き加えた状態でArch Linuxを起動→パスワード無しでroot権限が手に入る!ガハハ!」なのでまずい*1。何も書かないとデフォルトでeditor yesになってしまう。

僕は、電源ボタンを押したら即座にArch Linux(fallbackでない方)が選択されて起動するようにした。そのためには「タイムアウト:0」と「デフォルト:Arch Linux」の2つを指定する。タイムアウトの方は何も書かなくても自動で0になる。書くとしたら「timeout 0」。デフォルトのローダは「default (ファイル名)」と書いて指定する。ファイル名のところにはさっき作ったファイル名arch.confの拡張子を除いた部分(つまりarch)を書く。「i」で入力開始、Escで入力終了。

最終的にloader.confの中身は次のようになる:

editor no
default arch

:wq」で保存終了。他の設定例:

editor no
timeout 3
default arch

起動してから3秒間選択肢が表示され、その間に何もしないとArch Linuxが起動する。ここで表示される選択肢をtimeout 0でも表示するには起動時にスペースキーを押す。

6. 再起動

exitしてUSBを抜いて再起動。

exit

reboot

起動したら

login: root

password: (パスワード)

でログイン。

  7. 諸設定

ユーザを追加する。

useradd -m -G wheel (ユーザ名)

作ったユーザのパスワードを設定する。

passwd (ユーザ名)

sudoersファイルを設定する。

visudo

# %wheel ALL=(ALL) ALL と書かれた行を探し、コメントアウト

さらに一度入力したパスワードが一定時間有効なままなのが嫌なのでDefaults timestamp_timeout=0を追記した。別に構わないならしなくて良い。

そうしたら今作ったユーザでログインし直す。

exit

*1:やってみた。Welcome to Arch Linux! の代わりに[root@archlinux /]# と表示され、パスワードが変更できた。

Arch Linux

今年の5月7日にWindowsを捨ててArch Linuxに切り替えてからしばらく経ったので、今の所どういう感じで使っているのかをメモしておきたいと思います。

 

最初はBIOS, MBRだったけど8/26にUEFI, GPTでやり直した。パーティションは/boot(512M),  swap(1G), /(残り464.3G)。メモリ4Gもあるんだからswapとか作るだけ無駄だった。次気をつける

 

ブートローダはsystemd-boot。espは/boot。esp/loader/entriesにはarch.confとarch-fallback.confの2つを書いて、timeoutとか面倒だったのでesp/loader/loader.confにはdefaultだけ書いといた。

 

キーマップはDvorak派。/etc/vconsole.confには

KEYMAP=dvorak-programmer.map
FONT=Lat2-Terminus16

と書いた。ちなみにテンキーがないので数字入力するのちょっと面倒。

 

ここからしばらく有線接続を使う。dhcpcdをsystemd startしたら普通にping通った。普段は部屋でスタンドアローン、ネット環境が欲しいときだけ家のリビングでイーサネットみたいなのを数カ月間続けた。

 

git, wgetをインストール。

 

pacman使ってたら周りの人が他のを使うことを勧められた。たくさんあってどれを選べばいいのか分からなかったので常務くんイチオシのyayをインストール。yay自体が公式リポジトリに無いのでgitで入れた。

 

vim派なのでvimを入れた。

C++書くのでboostを入れた。

haskell書くのでghcを入れた。

 

音を鳴らしたかったのでalsa-utilsを入れた。頑張ったら音が鳴った。/etc/modprobe.d/alsa-base.confと/etc/asound.confを頑張って書いて良い感じにした。結構大変だった。

 

コンソール上で画像を表示したかったのでfbidaを入れた。そのままだとfbiで画像が表示できなかった。解決策は何らかのXフォントをインストールして/usr/share/fontsに入れることだった。Notoフォントを入れた。

 

さて。この辺りでなんかGUI環境が欲しくなった。

でもそんなにGUIばっかりに頼りたくはなくて、好きなときにCLIに戻れるようにしたかった。

そこで、Xをインストールするもののディスプレイマネージャは入れず、GUI環境が欲しいときにstartxコマンドを打つことにした。ウィンドウマネージャはi3。

xorg-server、xorg-apps、xorg-init を入れる。この時点でstartxを打つとXが起動して即座に終了する。

Dvorak派なので/etc/X11/xorg.conf.dにあった00-keyboard.confを書き換えた。ここではdvorak-programmerは"dvp"という名前だった。

i3、dmenuを入れて普通にやった。

 

突然WiFiが使いたくなったのでnetworkmanagerを入れてnmtuiを使ってWiFiに繋いだ。

 

日本語が入力したくなったのでfcitx mozcを入れた。

 

動画再生にmplayerを入れた。

画像編集にmyPaintを入れた。

動画編集にflowbladeを入れた。

 

以上、大体こんな感じ。

ネタ切れ(・ω・`)

最近ブログに書くネタが無くてですね

 

最後に更新してからもう半年が経とうとしているんです。切れたんですよネタが。ホント、書くことがない。

 

もういくら考えてもネタが思い付かなくて。

 

それでですね、ついに苦肉の策に出ようと思ったんですよ。

 

「最近ブログに書くネタが無くてですね」とブログ自体に書くことにしたんです。ネタが無いということをネタにする。メタですね。

 

でもそれだけじゃつまらない。単に一度メタ化するだけじゃ、ネタが無いのと同じですよ。

 

そこでこうすることにしたんです。

 

「「最近ブログに書くネタが無くてですね」とブログ自体に書くことにしたんです。ネタが無いということをネタにする。メタですね。」という文をブログに書く。つまり2重のメタ化です。

 

さらに、「「「最近ブログに書くネタが無くてですね」とブログ自体に書くことにしたんです。ネタが無いということをネタにする。メタですね。」という文をブログに書く。つまり2重のメタ化です。」と書くと3重にメタ化することもできます。

 

ここで気付くわけですね、「さらに、「「「最近ブログに書くネタが無くてですね」とブログ自体に書くことにしたんです。ネタが無いということをネタにする。メタですね。」という文をブログに書く。つまり2重のメタ化です。」と書くと3重にメタ化することもできます。」と書いた時点で既に4重のメタ化が起こっていると。

 

ペアノの公理ってご存じですか?あれに似ていますね。つまり任意の自然数nに対してn重のメタ化が可能となります。

 

おや?私は「任意の自然数nに対してn重のメタ化が可能となります。」と書いてしまいました。これをここに書くと、いったい何重のメタ化になるんでしょう。

 

自然数の範囲を超えてしまいましたね。じゃあこれを、「どんな自然数よりも大きい数」としてωと名付けましょう。

 

さて、ω重のメタ化ができました。

 

ん?「ω重のメタ化ができました」?これは何重のメタ化ですか?

 

ωの次の数。ω+1です。私はω+1重のメタ化を行ったわけです。

 

はい、たった今「私はω+1重のメタ化を行ったわけです。」と書くことでω+2重のメタ化が行われましたね。

 

そして「はい、たった今「私はω+1重のメタ化を行ったわけです。」と書くことでω+2重のメタ化が行われましたね。」と書いたのでメタ化はω+3重です。

 

これを先程と同様に繰り返すと、自然数nに対しω+n重のメタ化が可能です。

 

……んん?「自然数nに対しω+n重のメタ化が可能です」???

 

そうですね。ω+ω、即ちです。

 

です」は2ω+1。「「です」は2ω+1。」は2ω+2。「「「です」は2ω+1。」は2ω+2。」は2ω+3。これを繰り返せば2ω+nが作れます。そして「2ω+nが作れます。」はです。

 

これを繰り返していくと、ωと任意の自然数nの積が作れます。

 

おや???「が作れます」?????(しつこいですよ)

 

はい、ω×ωですね。

 

これが順序数の世界です。

 

ω^ωも作ってみてください。

 

 

ではまた(・ω・`)

みんな大好き,ポインタ/配列/参照 ~多次元配列まとめ~

汎整数型(論理型(bool),文字型(charなど),整数型(intやlongなど))と浮動小数点型を合わせて算術型といい,算術型とvoid型を合わせて基本型といいます。基本型からは「ポインタ型」「配列型」「参照型」の3種類の組込み型が得られますが,この記事ではその中でも特に(単なる基本型へのポインタ型,配列型,参照型を除いた)2重以上のポインタ型,配列型,参照型の扱い方について説明します。constについては説明しません。templateについては説明しません。変数の型だけを見るので,変数名は全てハンガリアン記法の接頭辞のみとします。

まずCにあるポインタ型と配列型から先に説明します。

int i;

iはint型です。関数hoge(int)を宣言しておくと,hoge(i)でhoge(int)が呼び出されます。

intに*,[1],[2]を付けるとそれぞれ次の型が得られます。

int *pi, a1i[1], a2i[2];

piはint*型,a1iはint[1]型,a2iはint[2]型です。関数呼び出しではこれらは全て同じものとして扱われます。つまり関数hoge(int*)を宣言しておくと,hoge(pi),hoge(a1i),hoge(a2i)の全てにおいてhoge(int*)が呼び出されるということです。

int*に*,[1],[2]を付けるとそれぞれ次の型が得られます。

int **ppi, *a1pi[1], *a2pi[2];

ppiはint**型,a1piはint*[1]型,a2piはint*[2]型です。関数呼び出しではこれらは全て同じものとして扱われます。つまり関数hoge(int**)を宣言しておくと,hoge(ppi),hoge(a1pi),hoge(a2pi)の全てにおいてhoge(int**)が呼び出されるということです。

int[1]に*,[1],[2]を付けるとそれぞれ次の型が得られます。

int (*pa1i)[1], a1a1i[1][1], a2a1i[2][1];

pa1iはint(*)[1]型,a1a1iはint[1][1]型,a2a1iはint[2][1]型です。関数呼び出しではこれらは全て同じものとして扱われます。つまり関数hoge(int(*)[1])を宣言しておくと,hoge(pa1i),hoge(a1a1i),hoge(a2a1i)の全てにおいてhoge(int(*)[1])が呼び出されるということです。hoge(int**)に渡したいときはキャストします。

int[2]に*,[1],[2]を付けるとそれぞれ次の型が得られます。

int (*pa2i)[2], a1a2i[1][2], a2a2i[2][2];

pa2iはint(*)[2]型,a1a2iはint[1][2]型,a2a2iはint[2][2]型です。関数呼び出しではこれらは全て同じものとして扱われます。つまり関数hoge(int(*)[2])を宣言しておくと,hoge(pa2i),hoge(a1a2i),hoge(a2a2i)の全てにおいてhoge(int(*)[2])が呼び出されるということです。

変数Aの型がTであるとき,&AはT*型です。即ちint(**[2])[3]型変数a3ppa2iのアドレス&a3ppa2iはint(**(*)[2])[3]型です。

変数Bの型がT*であるとき,*BはT型です。即ちint(*(**)[4])[2]型変数a2pa4ppiの参照*a2pa4ppiはint(*(*)[4])[2]型です。

変数を配列型にキャストすることはできません。reinterpret_castとかそういう問題ではなく,言語仕様上絶対に不可能です。

int a0i[0]はint[0]型です。

sizeof iが4,sizeof piが8であった場合,sizeof a1iは4×1=4,sizeof a2iは4×2=8,sizeof ppiは8,sizeof a1piは8×1=8,sizeof a2piは8×2=16,sizeof pa1iは8,sizeof a1a1iは4×1×1=4,sizeof a2a1iは4×1×2=8,sizeof pa2iは8,sizeof a1a2iは4×2×1=8,sizeof a2a2iは4×2×2=16です。配列+整数のsizeof,即ちsizeof(a2i+1)やsizeof (a2a1i+0)などは全てsizeof pi(=8)に等しくなります。sizeof *a2a1iは*a2a1iがint[1]型なのでsizeof a1i(=4)に等しくなります。sizeof *(a2a1i+0)も同じくsizeof a1iに等しくなります。a2a1i[0]は*(a2a1i+0)の糖衣構文なので,sizeof a2a1i[0]も同じくsizeof a1iに等しくなります。

C++にはポインタ,配列に加え,参照というものがあります。

関数hoge_cpp(int&)をhoge_cpp(i)で,関数hoge_cpp(int&&)をhoge_cpp(i+0)で,関数hoge_cpp(int*&)をhoge_cpp(pi)で,関数hoge_cpp(int*&&)をhoge_cpp(pi+0)やhoge_cpp(a1i)やhoge_cpp(a1i+0)で,関数hoge_cpp(int(&)[1])をhoge_cpp(a1i)で,関数hoge_cpp(int(&)[2])をhoge_cpp(a2i)で呼び出せます。hoge_cpp(a1i)でhoge_cpp(int(&)[2])を呼び出すことはできないので,テンプレートを使って配列の大きさごとに関数を作れば(使うたびに関数が増えますが)関数内で配列の大きさを知ることができます。

とりあえずこの記事はここまでです。部分的に情報密度が高くなってしまいましたが,その一部でもあなたの役に立てば幸いです。

プログラマーじゃなくても分かる,Krileのクエリの書き方

2018/9/28追記

Krile は死んだ。

 

 

twitterを本気でやるならやっぱりKrile Starryeyesを使うのが一番。

セットアップの仕方は以下のサイトに書かれています。

Krile StarryEyesのセットアップの仕方 - -

Krileではタブというものがあり,「自分がフォローしている人のツイートを表示するタブ」「自分宛てのリプを表示するタブ」「自分の名前が含まれるツイートを全て表示するタブ」など,一つ一つのタブに表示するツイートを指定することができます。

しかし指定するための「クエリ」の書き方が分からない…!!という人も多いのではないでしょうか。

実はクエリの書き方は次のサイトに全て書かれています。

KQ_Overview · karno/StarryEyes Wiki · GitHub

しかしこれ…文体がプログラマー向けなんですよね。

まぁクエリを書くのはプログラミングと同じなので仕方ない。

でもKrileを使う人がみんなプログラマーというわけではありません。なのでここでは,プログラマーでない人のためにKrileのクエリの書き方を説明したいと思います。

(おっと…プログラミングが小学校で義務教育化されるんだっけ?まぁそうなったらこういう記事の需要も無くなっていくのでしょうね…)

クエリの構成

Krileのクエリは前半部分と後半部分に分かれています。前半が「from」で始まる「ソースクエリ」,後半が「where」で始まる「フィルタクエリ」です。例えばクエリが「from local where text contains "love"」なら「from local」がソースクエリで,「where text contains "love"」がフィルタクエリです。

ソースクエリではツイートを取得する範囲を指定し,そのうちフィルタクエリで指定した条件を満たすものだけがタブに表示されます。

例えばソースクエリでは「タイムラインに流れてくる全てのツイート」「検索でヒットした全てのツイート」「特定の人の全てのツイート」などが指定できて,フィルタクエリでは「本文中に~を含む」「~RT以上されている」「リスト~に登録されていてIDに数字0を含まない人のうち~人以上にいいねされている」などが細かく指定できます。

ソースクエリ

fromの後に書ける単語がいくつか決まっています。

local (allと書いても同じ)

「from local」とすると,Krileを使っている間に一度でも保存されたツイート全てが対象になります。タイムラインやリプライなど自分に関連しているツイートならFF内外は関係ないのですが,twitter上のツイートが全て検索できるわけではありません。

「from local: ~」のように,コロン「:」で区切ってその後にKrileのタブ名を指定すると,そのタブ内にある全てのツイートが対象になります。*1

 home

「from home」とすると,タイムライン(フォローしている人のツイート)が対象になります。

複数のアカウントを使っている場合は,「from home: "57tggx"」のように,コロン「:」で区切った後「"」2つで囲った部分にIDを書くと,そのアカウントのタイムラインだけが対象になります。

 mention (mentions, reply, repliesも全て同じ)

自分宛の返信が対象になります。複数のアカウントを使っている場合はhomeと同じように「from mention: "ID"」でアカウントを指定します。

message (messages, dm, dmsも全て同じ)

自分宛のDMと自分が送ったDMが対象になります。複数のアカウントを使っている場合はhomeと同じように「from message: "ID"」でアカウントを指定します。

list

指定したリストのツイートが対象になります。「/」で区切って「from list:"自分のID/リスト名"」と書きます。他の人の作ったリストの場合は,自分の持っているアカウントから一つ選んで,「from list:"自分のID/リスト作成者のID/リスト名"」とします。

search (findも同じ)

「from search:"~"」とするとtwitter検索でヒットした全てのツイートが対象になります。普通のtwitter検索とほぼ同じですが,「"そんなの聞いてない"」のような完全一致検索をするときは中の「"」を「\"」(円マーク+「"」)に書き換えて「from search:" \"そんなの聞いてない\" "」とします。

track (streamも同じ)

「from track:"~"」でもツイート検索ができます。こちらはストリーム検索といって,検索結果に新しいツイートが自動で読み込まれ続けるため,サーバに負荷がかかりません。

conv (conversation, talk, treeも同じ)

twitterでは,全てのツイートにID番号が振られています。「from conv:"01234567890123456789"」のようにIDを指定すると,そのツイートとそれに対する全ての返信(リプライツリー)が対象になります。

user

特定の誰かに張り付くならこれ。「from user:"57tggx"」でIDを指定するか,「from user:"#808612487507513344"」(「#」を忘れないこと)で固有IDを指定します。

フィルタクエリ

フィルタクエリを省略すると,取得した全てのツイートがそのまま表示されます。

フィルタクエリには色々な文が書けます。

文の例とその意味,同じと見なせる単語は次の通りです:

text="334" 本文が「334」と一致する textとbody, =と==
text->"334" 本文に「334」が含まれる ->とcontains
text startswith "334" 本文が「334」で始まる startswithとstartwith
text endswith "334" 本文が「334」で終わる endswithとendwith
text->"windows" 本文に「windows」が含まれる(大文字小文字を区別しない)  
caseful text->"windows" 本文に「windows」が含まれる(大文字小文字を区別する)  
favs=3 ふぁぼ数が3 favsとfavorites, favorer, favorers
favs>3 ふぁぼ数が3より多い  
rts>3 RT数が10より多い rtsとretweets, retweeters
rts>favs RT数がふぁぼ数より多い  
rts*rts>favs*2+5 RT数の2乗がふぁぼ数の2倍+5より多い  
rt リツイートである*2 rtとretweet, isretweet, is_retweet
user=@57tggx ツイート主が@57tggx  
user="57tggx" ツイート主のIDが57tggx*3 userとuser.screen_name
user->"tg" ツイート主のIDに「tg」が含まれる  
user=808612487507513344 ツイート主の固有IDが808612487507513344*4 userとuser.id
user.status>100 ツイート主のツイート数が100より多い*5 .statusと.statuses, .statuscount, .status_count, .statusescount, .statuses_count
user.following>100 ツイート主のフォロー数が100より多い .followingと.friend, .friends, .followings, .friendscount, .friends_count, .followingscount, .followings_count
user.follower>100 ツイート主のフォロワー数が100より多い .followerと.followers, .followerscount, .followers_count
user.fav>100 ツイート主のふぁぼ数が100より多い .favと.favs, .favcount, .favorite, .favorites, .favscount, .favs_count, .favoritescount, .favorites_count
user.list>100 ツイート主のリスト被登録数が100より多い .listと.listed, .listcount, .list_count, .listedcount, .listed_count
user.screenname="57tggx" ツイート主のスクリーンネームが「57tggx」 .screennameと.screen_name
user.name->"ビタリスト" ツイート主のハンドルネームに「ビタリスト」が含まれる .nameと.username
user.bio->"数ぽよ" ツイート主のプロフィールに「数ぽよ」が含まれる .bioと.desc, .description
user.loc="どこでもない" ツイート主の設定所在地が「どこでもない」 .locと.location
user.lang="en" ツイート主の設定言語が「en」(=英語) .langと.language
user.protected 鍵アカウント .protectedと.isprotected, .is_protected
via->"twitter web client" twitter web clientから投稿されている*6 viaとfrom, source, client

数字に対して使える記号は次の通りです:「+」(加),「-」(減),「*」(乗),「/」(除),「=」(イコール, 「==」も同じ),「<」(小なり),「<=」(小なりイコール),「>」(大なり),「>=」(大なりイコール),「!=」(ノットイコール)。

複数の条件を重ねるときは「&」「|」を使います。例えば「user.following > 100 | user.follower > 100」は「フォロー数が100より多い」「フォロワー数が100より多い」の少なくとも一方を満たしているという意味で,「user.protected & user.status<=100」は「鍵アカウント」「ツイート数が100以下」の両方を満たしているという意味です。「&&」は「&」,「||」は「|」と同じ意味です。

条件を否定するには「!」を使います。「!user.protected」は「鍵アカウントでない」という意味です。

優先順位は括弧で指定します。「!(text->"57tggx" & user.name!="57tggx")」は「「「text->"57tggx"」かつ「user.name!="57tggx"」」でない」という意味になります。

 ここまでで大体のことはできると思います。とりあえずこの記事はこれで終わりですが,興味があったらこの先を自分で調べてみて下さい。

*1:複数のタブに同じ名前を付けることができますが,そのときは指定した名前を持つタブのうち1つのみが対象となります

*2:Krileではリツイートが元ツイートと別に扱われます。フィルタにrtを指定すると,元ツイートは表示されずリツイートのみが表示されます。

*3:「@57tggx」と「=」で結ばれたときの「user」と,「"57tggx"」と「=」で結ばれたときの「user」は微妙に違う意味になります。前者は「ユーザオブジェクト」,後者は「文字列」です。userはもともとユーザオブジェクトですが,文字列と比較しようとしたときだけIDを表す文字列になります

*4:数値と比較しようとすると,今度は固有IDを表す数値になります

*5:ユーザオブジェクトの後に「.~」と続けることでそのアカウントに関する情報が得られます

*6:正確には「via名の中に"twitter web client"という文字列が含まれている」ですが,「->」を「=」に変えるとなぜか上手くいきません