Node.js+Express+Socket.IO入門
Socket.IO を使うと双方向の非同期通信が可能になります。今回はその入門編ということで、HTML の input 要素に入力した文字列をサーバに送信し、それをサーバで受信し、そのデータを再びクライアントに送信するプログラムを作成したので紹介します。Express や Socket.IO を使うことで、このようなプログラムをとても簡単に作成することができます。
♦ Express と Socket.IO のインストール(Windows)
まず Node.js をインストールしてください。Node.js をインストールすれば、npm も一緒にインストールされます。 続いて、D ドライブの直下に webapp フォルダを作成し、コマンドプロンプトから下記のように入力すると Express と Socket.IO をローカルインストールすることができます。
cd /d D:\webapp npm init(全てEnterでOK) npm install express socket.io
♦ プログラムの作成
データを送信・受信する関数は、クライアント側もサーバ側も次のようになります。
データの送信:emit(event_name, data)
データの受信:on(event_name, function (data) { ・・・・・ })
注)イベント名(event_name)は何でも構いませんが、送信する側と受信する側でイベント名を一致させる必要があります!
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Socket.IO</title>
</head>
<body>
<div>
<input id="Input" type="text">
<input type="button" value="送信" onclick="send();">
<output id="Output"></output>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
function send() {
socket.emit("ClientMessage", document.getElementById("Input").value);
}
socket.on("ServerMessage", function (data) { document.getElementById("Output").innerHTML = data["message"]; });
</script>
</body>
</html>
const webapp = require("express")();
const http = require("http").Server(webapp);
const io = require("socket.io")(http);
const port = 8080;
const host = "127.0.0.1";
webapp.get("/:file", (request, response) => response.sendFile("D:/webapp/public/" + request.params.file));
io.on("connection", (socket) => socket.on("ClientMessage", (data) => socket.emit("ServerMessage", {message:data})));
http.listen(port, host, console.log(`HTTP Server running at http://${host}:${port}/`));
D:\webapp\public\socket.io.html D:\webapp\socket.io.js
♦ Webアプリケーションの起動
コマンドプロンプトから下記のように入力すると、Web サーバのアプリケーション(socket.io.js)を起動させることができます。
cd /d D:\webapp
node socket.io.js
Ctrl+C(強制終了)
♦ ブラウザからWebサーバにアクセス
Web アプリケーション(socket.io.js)が起動したら、ブラウザのアドレスバーに下記のように入力してください。
http://localhost:8080/socket.io.html
すると、次のような画面が表示されます。
文字列を入力し、送信ボタンをクリックして、入力した文字列が表示されたら成功です^^
参考サイト
- Socket.IO
- Socket.IOの送信コマンドまとめ
- Node.jsからSocket.IOを使うための事前知識
- Node.js + Express + Socket.IOで遊んでみた
- Node.js + Express + Socket.IOで簡易チャットを作ってみる
- Node.js:Socket.IOのsendとemitの違い
AjaxとNode.js+Expressの連携
今回は、HTML の input 要素に二つの数値を入力し、それらを POST でサーバに送信し、Node.js + Express で受け取って、それらの加算を行い、その結果をクライアントに返すプログラムを紹介します。とても簡単です^^
♦ Express のインストール(Windows)
まず Node.js をインストールしてください。Node.js をインストールすれば、npm も一緒にインストールされます。続いて、D ドライブの直下にフォルダ webapp(フォルダ名は任意)を作成し、コマンドプロンプトから下記のように入力すると Express をローカルインストールすることができます。
cd /d D:\webapp npm init(全てEnter) npm install express
♦プログラムの作成
下記のようにプログラムを作成してください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Ajax</title>
</head>
<body>
<div>
<input id="Input1" type="text"> + <input id="Input2" type="text">
<button onclick="calculate('Input1', 'Input2', 'Output')">=</button>
<output id="Output"></output>
</div>
<script>
function calculate(input1, input2, output) {
const url = "/calculate";
const request = {};
request.input1 = document.getElementById(input1).value;
request.input2 = document.getElementById(input2).value;
const callback = function (response) { document.getElementById(output).innerHTML = response.output };
post(url, request, callback);
}
</script>
<script>
function post(url, request, callback) {
const xhr = new XMLHttpRequest();
xhr.onload = function () { callback(JSON.parse(this.responseText)) };
xhr.onerror = function () { console.error(this.statusText) };
xhr.open("post", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(JSON.stringify(request));
}
</script>
</body>
</html>
const host = "127.0.0.1";
const port = 8080;
const webapp = require("express")();
const bodyParser = require("body-parser");
webapp.use(bodyParser.json());
webapp.get("/:file", (request, response) => response.sendFile(__dirname + "/public/" + request.params.file));
webapp.post("/calculate", (request, response) => response.send({output:Number(request.body.input1) + Number(request.body.input2)}));
webapp.listen(port, host, console.log(`WebApp running at http://${host}:${port}/`));
D:\webapp\public\ajax.html D:\webapp\express.js
♦ サーバ側のWebアプリケーションを起動
コマンドプロンプトから下記のように入力し、サーバ側のWebアプリケーション express.js を起動させます。
cd /d D:\webapp node express.js
♦ ブラウザからクライアント側のWebアプリケーションにアクセス
サーバ側のWebアプリケーションが起動したら、ブラウザのアドレスバーに下記の URL を入力し、クライアント側のWebアプリケーション ajax.html にアクセスします。
http://localhost:8080/ajax.html
すると、次のような画面が表示されます。
数値を入力し、=ボタンをクリックして、結果が表示されたら成功です^^
参考サイト
- Node.js入門
- Windowsで nodejs のインストールからHelloWorld まで
- Windows10にNode.jsをインストールして自分だけのWEBサーバーを作る
- Expressチュートリアル
- Expressでの静的ファイルの提供
- Express で WebAPI を作る
- Expressのルーティング
- EJSテンプレートエンジンを使おう!
- npmのグローバルインストールとローカルインストール
- npmでグローバルインストールをしない方が良い理由
JavaScript:ドラッグ&ドロップでファイルを読み込む方法
テキストファイルをテキストエリアにドラッグ&ドロップすると、ファイルの内容がテキストエリアに表示されます。 以下のテキストエリアで試すことができます。(Shift_JIS 以外でエンコードされていると文字化けするので注意してください)
プログラムは次のようになります。
<!doctype html>
<html>
<body>
<textarea id="TextArea" cols="100" rows="20" ondragover="handleOnDragOver();" ondrop="handleOnDrop(displayText);">
Drag & drop here.
</textarea>
<script>
function handleOnDragOver() {
event.preventDefault();
}
function handleOnDrop(handleOnLoad) {
event.preventDefault();
const files = event.dataTransfer.files;
const fileReader = new FileReader();
fileReader.readAsText(files[0], "shift-jis"); // euc, utf-8, utf-16
fileReader.addEventListener("load", function () { handleOnLoad(this); });
}
function displayText(fileReader) {
document.getElementById("TextArea").innerHTML = fileReader.result;
}
</script>
</body>
</html>
参考サイト
JavaScript:文字列をファイルに保存する(書き込む)方法
Blob(binary large object)と a 要素を使って文字列(テキストデータ)をファイルに保存する関数 saveAsText を作成したので紹介します。もっと簡単な方法、readAsText があるのだから writeAsText のような関数もあるのではないかと世界中を探したのですがありませんでした。結局、国内でも海外でも Blob と a 要素を使っていました^^
注)ブラウザは Chrome(推奨)か Firefox をご利用ください。
String.prototype.saveAsText = function (file) {
const blob = new Blob([this], {type:"text/plain"});
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = file;
a.click();
};
"Hello!".saveAsText("sample.txt");
参考サイト
Swift:正規表現による文字列の抽出と置換
ここでは正規表現を使って、含有(include)、抽出(extractAll)、置換(replaceAll)を行う関数を紹介します。 これらの関数は、このページ末尾の“参考サイト”から集めてきたものです。尚、関数名や引数名は変えています。
また、関数 replaceAllByRule は、正規表現の中で(・・・)でグループ化された capturing group(subexpression)に置換ルールを適用することによって置換します。 下記の例では、文字列 "1+2,3+4,5+6" から正規表現 #"(\d+)\+(\d+)"# で2箇所のサブマッチ文字列を抽出し、Int型にキャストし、それらを加算した上で置換しています。結果は 3,7,11 となります。マッチした文字列全体は $0(0) で、i番目のサブマッチ文字列は $0(i) で取り出せます。
注)関数 replaceAllByRule は私の作品ですが、ライセンスフリーなので自由にご利用いただけます^^
注)下記のプログラムでは、文字列に #" ・・・ "# を使っているので、Swift 5 以降にしか対応していません。Swift 5 対応の paiza.IO では問題なく動作します。
import Foundation
extension String {
func include(pattern:String) -> Bool {
let regex = try! NSRegularExpression(pattern:pattern)
return regex.firstMatch(in:self, range:self.range(of:self)) != nil
}
func extractAll(pattern:String) -> [String] {
let regex = try! NSRegularExpression(pattern:pattern)
return regex.matches(in:self, range:self.range(of:self)).map { String(self[Range($0.range, in:self)!]) }
}
func replaceAll(pattern:String, with:String) -> String {
let regex = try! NSRegularExpression(pattern:pattern)
return regex.stringByReplacingMatches(in:self, range:self.range(of:self), withTemplate:with)
}
func replaceAllByRule(pattern:String, replacementRule:((Int) -> String) -> String) -> String {
let regex = try! NSRegularExpression(pattern:pattern)
var string = self
var location = 0
while let firstMatch = regex.firstMatch(in:string, range:NSRange(location..<string.count)) {
let range = firstMatch.range(at:0) // 最初にマッチした文字列全体のrange
let substring = { string.substring(with:firstMatch.range(at:$0)) } // $0番目のサブマッチ文字列を取り出す関数
let replacementString = replacementRule(substring)
string = string.replacingCharacters(in:range, with:replacementString)
location = range.location + replacementString.count
}
return string
}
}
print("Swift".include(pattern:#"S\w*t"#))
print("St Swt8Swit".extractAll(pattern:#"S\w*t"#))
print("St Swt8Swit".replaceAll(pattern:#"S\w*t"#, with:"Swift"))
print("1+2,3+4,5+6".replaceAll(pattern:#"(\d+)\+(\d+)"#, with:"$2-$1"))
print("1+2,3+4,5+6".replaceAllByRule(pattern:#"(\d+)\+(\d+)"#) { String(Int($0(1))! + Int($0(2))!) })
true ["St", "Swt8Swit"] Swift Swift 2-1,4-3,6-5 3,7,11
補足
extractAll の中の $0.range の挙動は、次のようになります。
import Foundation
let pattern = #"S\w*t"#
let string = "St Swt Swit"
let regex = try! NSRegularExpression(pattern:pattern)
print(regex.matches(in:string, range:string.range(of:string)).map { $0.range })
[{0, 2}, {3, 3}, {7, 4}]
参考サイト
- How to use regular expressions in Swift
- Swift extract regex matches
- iOS 置換 Swift 抽出正規表現の一致
- Swiftで正規表現を使って文字列を置換する
- Swift 3.0 での基本的な正規表現を行う
C++:多態性と関数の多重定義
ここではC++による多態性と関数の多重定義の例を紹介します。
多態性はオブジェクト指向プログラミングにおける素晴らしい技法の一つです。多態性を利用すると同じ関数名でオブジェクトに応じたオブジェクトの操作が可能になります。一方、多態性が利用できないとオブジェクトごとに関数名を変えてオブジェクトを操作しなければなりません。
以前、オブジェクト指向プログラミングの講習を受けたことがあるのですが、その時の講師は多態性を次のように説明していました。 一つの命令(関数名)でオブジェクトごとに異なる動作をさせることができる。例えば、鳥オブジェクトに“動け”と命令すれば鳥は空を飛ぶ、魚オブジェクトに“動け”と命令すれば魚は海を泳ぐ、と言ったぐあいです。
尚、C++の場合は、関数の多重定義を使って同様のことが実現できます。(下記の overloading.cpp を参照)
また、多人数でソフトウェアを開発する際、関数の多重定義が利用できる言語では、各プログラマは関数名の衝突を気にせずに関数名を付けることができます。
♥ 関数 calculate の多態性(polymorphism)の例
calculate の引数が、Operand1 のオブジェクトの場合には加算、Operand2 のオブジェクトの場合には乗算を実行します。
#include <iostream>
class Operand {
public:
virtual auto calculate() -> void;
};
class Operand1 : public Operand {
double x, y;
public:
Operand1(double x = 0, double y = 0);
auto calculate() -> void;
};
Operand1::Operand1(double x, double y) : x{x}, y{y} {}
auto Operand1::calculate() -> void {
std::cout << x + y << std::endl;
}
class Operand2 : public Operand {
double x, y;
public:
Operand2(double x = 0, double y = 0);
auto calculate() -> void;
};
Operand2::Operand2(double x, double y) : x{x}, y{y} {}
auto Operand2::calculate() -> void {
std::cout << x * y << std::endl;
}
auto calculate(Operand* operand) -> void {
operand->calculate();
}
auto main() -> int {
auto operand1 = new Operand1(1, 1);
auto operand2 = new Operand2(2, 2);
calculate(operand1); // -> 1 + 1 = 2
calculate(operand2); // -> 2 * 2 = 4
}
♥ 関数 calculate の多重定義(overloading)の例
上記と同様のことが、関数の多重定義を使っても実現できます。はっきり言って、C++の場合はこちらの方が簡単です^^
#include <iostream>
class Operand1 {
double x, y;
public:
Operand1(double x = 0, double y = 0);
auto calculate() -> void;
};
Operand1::Operand1(double x, double y) : x{x}, y{y} {}
auto Operand1::calculate() -> void {
std::cout << x + y << std::endl;
}
class Operand2 {
double x, y;
public:
Operand2(double x = 0, double y = 0);
auto calculate() -> void;
};
Operand2::Operand2(double x, double y) : x{x}, y{y} {}
auto Operand2::calculate() -> void {
std::cout << x * y << std::endl;
}
auto calculate(Operand1* operand1) -> void {
operand1->calculate();
}
auto calculate(Operand2* operand2) -> void {
operand2->calculate();
}
auto main() -> int {
auto operand1 = new Operand1(1, 1);
auto operand2 = new Operand2(2, 2);
calculate(operand1); // -> 1 + 1 = 2
calculate(operand2); // -> 2 * 2 = 4
}
g++ -std=c++17 -O3 *.cpp -o main.exe
Swift:多次元配列
Swiftによる多次元配列(multidimensional array)の作り方です。 以下のプログラムで、a1, a2, a3 は空配列(empty array)による初期化、b1, b2, b3 は要素数と初期値を指定した初期化です。
let n1 = 2
let n2 = 3
let n3 = 4
/* 1-dimensional array in Swift */
var a1 = [Double]()
var b1 = [Double](repeating:0, count:n1)
print(a1)
print(b1)
/* 2-dimensional array in Swift */
var a2 = [[Double]]()
var b2 = [[Double]](repeating:[Double](repeating:0, count:n2), count:n1)
print(a2)
print(b2)
/* 3-dimensional array in Swift */
var a3 = [[[Double]]]()
var b3 = [[[Double]]](repeating:[[Double]](repeating:[Double](repeating:0, count:n3), count:n2), count:n1)
print(a3)
print(b3)
参考サイト
- paiza.IO - Swift
- Array - SwiftDoc.org
- Array - Swift API Reference
- Array reference guide for Swift
- Create a two-dimensional array at runtime
- Swift4:ArrayとNSArray・NSMutableArrayの違い
- arrays 辞書 Swift の2次元配列