scanfで苦戦した

まえおき

C言語の話。
コンパイラgcc
scanfを複数回実行すると入力バッファに改行文字が残って意図しない動作をすることがある。
その回避策として以下の2つがあった。

  • 代入抑止文字を使う方法
scanf("%c%*c",&c);
  • 空白文字を使う方法
scanf(" %c",&c);

ほんだい

目的

上記の方法を使って以下のようなことを実現する。

  • 入力されたもののうち先頭にある文字だけを読み取る。
  • どんな入力に対しても対処できるようにする。

実装

  • 代入抑止文字を使う方法
scanf("%c%*[^\n]%*c", &ch);

先頭の文字を読み取り、入力バッファに残ってるものを読み捨てる。

#include <stdio.h>

int main(void) {
  char ch;
  while (1) {
    scanf("%c%*[^\n]%*c", &ch);
    printf("ch:%c;%d\n", ch, ch);
    printf("--------------------\n");
  }
  return 0;
}

実行結果

q
ch:q;113
strchr(str, ch):;4196100
--------------------
w
ch:
;10
strchr(str, ch):;0
--------------------
e
ch:e;101
strchr(str, ch):;4196102
--------------------
rty
ch:
;10
strchr(str, ch):;0
--------------------

うまくいかない。

  • 空白文字を使う方法
scanf(" %c%*[^\n]", &ch);

先頭の空白文字と改行を読み捨ててから、先頭の文字を読み取り、入力バッファに残っている改行文字までを読み捨てる。

#include <stdio.h>

int main(void) {
  char ch;
  while (1) {
    scanf(" %c%*[^\n]", &ch);
    printf("ch:%c;%d\n", ch, ch);
    printf("--------------------\n");
  }
  return 0;
}

実行結果

q
ch:q;113
strchr(str, ch):;4196100
--------------------
w
ch:w;119
strchr(str, ch):;4196101
--------------------
e
ch:e;101
strchr(str, ch):;4196102
--------------------
rty
ch:r;114
strchr(str, ch):;4196103
--------------------

よさそう。

まとめ

scanfはなるべく使いたくない

NodeListは配列じゃないよって話


というわけで調べてみるとこんなのが出てきた。

NodeList are used very much like arrays and it's tempting to invoke Array.prototype methods on them, however NodeList objects don't have any of the familiar Array methods.
NodeList - Web APIs | MDN

簡単に言えば、document.querySelectorAll()で取得したNodeListは配列じゃなくて"配列っぽい"オブジェクトということ。配列と同じように扱うと痛い目みるよってわけ。

解決策としては配列に変換すればいいのだけど色々方法があるみたい。

  • apply(), call()を使う方法
var nodeList = document.querySelectorAll("div"); //適当に取得
Array.isArray(nodeList); // false => not Array
Array.isArray(Array.apply(nodeList)); // true => Array
Array.isArray(Array.call(nodeList)); // true => Array
Array.isArray(Array.prototype.slice.apply(nodeList)); // true => Array
Array.isArray(Array.prototype.slice.call(nodeList)); // true => Array
Array.isArray([].slice.apply(nodeList)); // true => Array
Array.isArray([].slice.call(nodeList)); // true => Array
  • Spread Operator(...)を使う方法
Array.isArray([...nodeList]); // true => Array Firefoxのみ
  • Array.from()を使う方法
Array.isArray(Array.from(nodeList)); // true => Array Firefoxのみ

下の2つはまだサポートしてないブラウザが多いので一番上のが実用的みたい。
個人的には一番下が好み。

ツイートを10000文字にするブックマークレットを作った

こんにちは、nimius(@nimiusxp)です。初投稿です。

最近Twitterでツイートの最大文字数が10000文字になるのではないかという話題がありました。反対意見が多いようですが迷惑ならなければいいかなと思っています。

さて、今回はタイトルにある通り実際にTL上に10000文字のツイートで埋めてみたらどうなるかをブックマークレットで試してみました。コードは以下のようになります。

javascript:(function(){
    //追加する適当な文字列
    var extention = '試合を終えて家路へ向かうサッカー部員達。疲れからか、不幸にも黒塗りの高級車に追突してしまう。後輩をかばいすべての責任を負った三浦に対し、車の主、暴力団員谷岡に言い渡された示談の条件とは・・・。';
    //ツイートのテキスト部分に当たるノードを取得
    var tweetTextsNode = document.querySelectorAll('p.tweet-text');
    //ノード群を配列にする。
    var tweetTexts = Array.apply(null,tweetTextsNode);
    tweetTexts.forEach(function(item){
        //10000文字前後になるまで文字列を追加する
        for(var i = 0; i &lt; 10000; i+=extention.length){
            item.textContent += extention
        }
    });
})();


10000文字にしったー

上のリンクをブックマークして、TwiiterTweetDeck内で使うことができます。

実際に使ってみましたが、1ツイートで画面が埋まってしまって非常に鬱陶しいです。下の画像はtweetdeck。

f:id:nimius:20160110165843p:plain

以上です。