- 投稿日:2019-10-01T22:50:21+09:00
技術書典の本を検索できるアプリを作ってみた~サーバーサイド 編~
はじめに
この記事は、時間ができた学生が暇つぶしに「技術書典の本を検索できるアプリを作ってみた」というものです。
技術書典に参加する前にある程度購入する本を決めると思うのですが、その際に欲しい技術について書いてある本を探したいと思うはずです。サークル一覧から本を探すのはとても大変で時間が足りません。そこでスクレーピングしてデータ収集し、検索できるアプリを開発してみました(自己満)。
この記事ではサーバーサイドについて書きます。次の記事で「Androidアプリを作ってみた」を書きたいと思います。サーバーサイドの流れ
- Pythonでデータを収集する
I.技術書典のサークルリスト からURL情報を収集する
II. 集めたURLにアクセスしてそれぞれのサークルが出している本の情報を収集する- 収集したデータをDBに保存する
- Goでサーバーを立てる
1. Pythonでデータ収集
I. 技術書典のサークルリスト からURL情報を収集する
技術書典のサークルリストの<a>タグをひたすら保存するコード
collect_url.py# coding: UTF-8 from bs4 import BeautifulSoup from selenium import webdriver import chromedriver_binary from selenium.webdriver.chrome.options import Options # ブラウザのオプションを格納する変数 options = Options() # Headlessモードを有効にする options.set_headless(True) # ブラウザを起動する driver = webdriver.Chrome(chrome_options=options) # ブラウザでアクセスする driver.get("https://techbookfest.org/event/tbf07/circle") # HTMLを文字コードをUTF-8に変換してから取得 html = driver.page_source.encode('utf-8') # BeautifulSoupで扱えるようにパース soup = BeautifulSoup(html, "html.parser") # ファイル出力 file_text = open("url_data.txt", "w") elems = soup.find_all("a") for elem in elems: print(elem.get('href'),file=file_text) file_text.close()II. 集めたURLにアクセスしてそれぞれのサークルが出している本の情報を収集する
1.で集めたURLにアクセスし、
出店しているサークル名、配置場所、ジャンル、ジャンル詳細、サークル画像、出品している本の名前、内容
のデータを収集する。(残念ながらペンネームは集められなかった。html にclass or idを貼って無いから面倒)collect_data.py# coding: UTF-8 from bs4 import BeautifulSoup from selenium import webdriver import chromedriver_binary from selenium.webdriver.chrome.options import Options import pickle import sys # データを保存する i = 0 sys.setrecursionlimit(10000) with open('../data/getData.txt', 'wb') as ff: # 保存するデータ save_datas = [] # ブラウザのオプションを格納する変数 options = Options() # Headlessモードを有効にする options.set_headless(True) # ブラウザを起動する driver = webdriver.Chrome(chrome_options=options) urlHeader = "https://techbookfest.org" pathfile = "../data/url_data.txt" with open(pathfile) as f: for _path in f: i += 1 url = urlHeader + _path print(i,url) # ブラウザでアクセスする driver.get(url) # HTMLを文字コードをUTF-8に変換してから取得 html = driver.page_source.encode('utf-8') # BeautifulSoupで扱えるようにパース soup = BeautifulSoup(html, "html.parser") circle = soup.find(class_="circle-name").string arrange = soup.find(class_="circle-space-label").string genre = soup.find(class_="circle-genre-label").string keyword = soup.find(class_="circle-genre-free-format").string circle_image = soup.find(class_="circle-detail-image").find(class_="ng-star-inserted") book_title = [] for a in soup.find_all(class_="mat-card-title"): book_title.append(a.string) book_content = [] for a in soup.find_all(class_="products-description"): book_content.append(a.string) for title, content in zip(book_title, book_content): data = [circle,circle_image['src'],arrange,genre,keyword,title,content,url] save_datas.append(data) pickle.dump(save_datas,ff)2. 収集したデータをDBに保存する
ファイルに保存したデータを取得し、MySQLにInsertするだけのプログラムです。Insertするだけなので適当なプログラムになってしまった。
insertDB.py# coding: UTF-8 import MySQLdb import pickle # データベースへの接続とカーソルの生成 connection = MySQLdb.connect( host='0.0.0.0', user='user', passwd='password', db='techBook') cursor = connection.cursor() # id, circle, circle_image, arr, genere, keyword, title, content with open('../data/getData.txt','rb') as f: load_datas = pickle.load(f) for load_data in load_datas: data = [] if load_data[6] == None: for dd in load_data: if dd == None: continue dd = dd.replace('\'','') data.append(dd) sql = "INSERT INTO circle (circle, circle_image, arr, genere, keyword, title, circle_url) values ('" + data[0] + "','" + data[1] + "','" + data[2]+"','" + data[3]+"','" + data[4]+"','" + data[5]+"','" + data[6]+"')" else: for dd in load_data: dd = dd.replace('\'','') data.append(dd) sql = "INSERT INTO circle (circle, circle_image, arr, genere, keyword, title, content, circle_url) values ('" + data[0] + "','" + data[1] + "','" + data[2]+"','" + data[3]+"','" + data[4]+"','" + data[5]+"','" + data[6]+"','" + data[7]+"')" print(sql) cursor.execute(sql) # 保存を実行 connection.commit() # 接続を閉じる connection.close()3. Goでサーバーを立てる
Pythonで書いてもよかったのですが、気分的にGoで書きました。
レイアードアーキテクチャで書いています。(宣伝)
ファイル数が多いので全部載せることはできませんでした。Githubを参照ください。
検索はSQLの部分一致検索で行います。SELECT * FROM circle where content like '%swift%';取得したデータをjson形式で返して終わりです!!
[request] { "keyword":"..." } [response] { "result": [ { "CircleURL": "...", "Circle": "...", "CircleImage": "...", "arr": "...", "Genere": "...", "Keyword": "...", "Title": "...", "Content": "..." }, ] }終わりに
久々にPythonを書いた気がします。全体的に書いてて楽しかったです。今回書いたコードはこちら。
読んでいただきありがとうございました。次回のAndroid編をお楽しみに!!
- 投稿日:2019-10-01T22:50:21+09:00
技術書典の本を検索できるアプリを作ってみた~サーバーサイド 編(Python, Go)~
はじめに
この記事は、時間ができた学生が暇つぶしに「技術書典の本を検索できるアプリを作ってみた」というものです。
技術書典に参加する前にある程度購入する本を決めると思うのですが、その際に欲しい技術について書いてある本を探したいと思うはずです。サークル一覧から本を探すのはとても大変で時間が足りません。そこでスクレーピングしてデータ収集し、検索できるアプリを開発してみました(自己満)。
この記事ではサーバーサイドについて書きます。次の記事で「Androidアプリを作ってみた」を書きたいと思います。サーバーサイドの流れ
- Pythonでデータを収集する
I.技術書典のサークルリスト からURL情報を収集する
II. 集めたURLにアクセスしてそれぞれのサークルが出している本の情報を収集する- 収集したデータをDBに保存する
- Goでサーバーを立てる
1. Pythonでデータ収集
I. 技術書典のサークルリスト からURL情報を収集する
技術書典のサークルリストの<a>タグをひたすら保存するコード
collect_url.py# coding: UTF-8 from bs4 import BeautifulSoup from selenium import webdriver import chromedriver_binary from selenium.webdriver.chrome.options import Options # ブラウザのオプションを格納する変数 options = Options() # Headlessモードを有効にする options.set_headless(True) # ブラウザを起動する driver = webdriver.Chrome(chrome_options=options) # ブラウザでアクセスする driver.get("https://techbookfest.org/event/tbf07/circle") # HTMLを文字コードをUTF-8に変換してから取得 html = driver.page_source.encode('utf-8') # BeautifulSoupで扱えるようにパース soup = BeautifulSoup(html, "html.parser") # ファイル出力 file_text = open("url_data.txt", "w") elems = soup.find_all("a") for elem in elems: print(elem.get('href'),file=file_text) file_text.close()II. 集めたURLにアクセスしてそれぞれのサークルが出している本の情報を収集する
1.で集めたURLにアクセスし、
出店しているサークル名、配置場所、ジャンル、ジャンル詳細、サークル画像、出品している本の名前、内容
のデータを収集する。(残念ながらペンネームは集められなかった。html にclass or idを貼って無いから面倒)collect_data.py# coding: UTF-8 from bs4 import BeautifulSoup from selenium import webdriver import chromedriver_binary from selenium.webdriver.chrome.options import Options import pickle import sys # データを保存する i = 0 sys.setrecursionlimit(10000) with open('../data/getData.txt', 'wb') as ff: # 保存するデータ save_datas = [] # ブラウザのオプションを格納する変数 options = Options() # Headlessモードを有効にする options.set_headless(True) # ブラウザを起動する driver = webdriver.Chrome(chrome_options=options) urlHeader = "https://techbookfest.org" pathfile = "../data/url_data.txt" with open(pathfile) as f: for _path in f: i += 1 url = urlHeader + _path print(i,url) # ブラウザでアクセスする driver.get(url) # HTMLを文字コードをUTF-8に変換してから取得 html = driver.page_source.encode('utf-8') # BeautifulSoupで扱えるようにパース soup = BeautifulSoup(html, "html.parser") circle = soup.find(class_="circle-name").string arrange = soup.find(class_="circle-space-label").string genre = soup.find(class_="circle-genre-label").string keyword = soup.find(class_="circle-genre-free-format").string circle_image = soup.find(class_="circle-detail-image").find(class_="ng-star-inserted") book_title = [] for a in soup.find_all(class_="mat-card-title"): book_title.append(a.string) book_content = [] for a in soup.find_all(class_="products-description"): book_content.append(a.string) for title, content in zip(book_title, book_content): data = [circle,circle_image['src'],arrange,genre,keyword,title,content,url] save_datas.append(data) pickle.dump(save_datas,ff)2. 収集したデータをDBに保存する
ファイルに保存したデータを取得し、MySQLにInsertするだけのプログラムです。Insertするだけなので適当なプログラムになってしまった。
insertDB.py# coding: UTF-8 import MySQLdb import pickle # データベースへの接続とカーソルの生成 connection = MySQLdb.connect( host='0.0.0.0', user='user', passwd='password', db='techBook') cursor = connection.cursor() # id, circle, circle_image, arr, genere, keyword, title, content with open('../data/getData.txt','rb') as f: load_datas = pickle.load(f) for load_data in load_datas: data = [] if load_data[6] == None: for dd in load_data: if dd == None: continue dd = dd.replace('\'','') data.append(dd) sql = "INSERT INTO circle (circle, circle_image, arr, genere, keyword, title, circle_url) values ('" + data[0] + "','" + data[1] + "','" + data[2]+"','" + data[3]+"','" + data[4]+"','" + data[5]+"','" + data[6]+"')" else: for dd in load_data: dd = dd.replace('\'','') data.append(dd) sql = "INSERT INTO circle (circle, circle_image, arr, genere, keyword, title, content, circle_url) values ('" + data[0] + "','" + data[1] + "','" + data[2]+"','" + data[3]+"','" + data[4]+"','" + data[5]+"','" + data[6]+"','" + data[7]+"')" print(sql) cursor.execute(sql) # 保存を実行 connection.commit() # 接続を閉じる connection.close()3. Goでサーバーを立てる
Pythonで書いてもよかったのですが、気分的にGoで書きました。
レイアードアーキテクチャで書いています。(宣伝)
ファイル数が多いので全部載せることはできませんでした。Githubを参照ください。
検索はSQLの部分一致検索で行います。SELECT * FROM circle where content like '%swift%';取得したデータをjson形式で返して終わりです!!
[request] { "keyword":"..." } [response] { "result": [ { "CircleURL": "...", "Circle": "...", "CircleImage": "...", "arr": "...", "Genere": "...", "Keyword": "...", "Title": "...", "Content": "..." }, ] }終わりに
久々にPythonを書いた気がします。全体的に書いてて楽しかったです。今回書いたコードはこちら。
読んでいただきありがとうございました。次回のAndroid編をお楽しみに!!
- 投稿日:2019-10-01T22:27:30+09:00
CGOを含むgolangのプログラムをラズパイ向けにクロスビルドする
Ubuntu 18.04 を使用しています。
CGOを含む以下のプログラムをgolangのプログラムをラズパイ向けにクロスビルドするには
cgo_test.gopackage main import ( "fmt" ) // #cgo LDFLAGS: -lm // #include <math.h> import "C" func main() { fmt.Printf("sqrt(3) = %f\n", C.sqrt(C.double(3))) }まずクロスコンパイラのインストール
sudo apt install g++-arm-linux-gnueabihfgccしかいらなくてもあえてg++をインストールすることでクロスのlibcなど必要なものが全て芋づる式にインストールされます。
go build では以下のように環境変数を指定します。
CC=arm-linux-gnueabihf-gcc GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 go build -o cgo_test.armv6ポイントは
CC=
でCのクロスコンパイラを指定することと、CGO_ENABLED=1
をつけること。詳しくは
https://golang.org/cmd/cgo/関連
x86_64のUbuntuでC/C++のソースコードをARM/ARM64用にクロスコンパイルしてQEMUで実行する方法のまとめ
昔はARM用にビルドしたgolangの実行ファイルはqemuでは動かなかったのですが、今はそんなことなくてqemuで動かすことができるようになっています。
- 投稿日:2019-10-01T19:55:55+09:00
熨斗(のし)の王様を作ったときに気をつけたこと
まとめ
- のし王というWebサービスを作った。
- のし作成サービスが既に存在する中で、下記に気をつけたというお話。
- サービス作成のきっかけになった不満点・ニーズをもれなく仕様に落とし込む
- 仕様策定時は技術的な楽さに甘えず、ユーザー体験を優先する
- 上記を実現するため必要最低限の技術を選定する
不満点の解消、ニーズを仕様に落とし込む
- ちょっとした贈り物に「のし」をつけたかった。
- 既存サービスは、以下の点で不満が残った。
- 「のし紙」のテンプレート(背景画像)だけが提供されており、Wordなどに貼り付けた後、自分で文字を描かないとダメだった
- Web上で任意の文字まで入れられるサービスでは、最後になるまで仕上がり具合がが分からなかった
- 最終画像にサービス名のロゴが入ってしまい、贈り物には不向きだった
- フォントがしょぼかった
- 水引き(背景画像)や表書き(御礼などの上部の文字)をどう選んでよいか分からなかった
- 不満点の解消をもれなく仕様に落とし込んだ。
- 背景画像と任意の文字を組み合わせてPDFで出力できるようにする
- 最終出力結果には広告を入れない
- 有料でもカッコいいフォントを採用する
- 用途に応じて自動で「水引き」と「表書き」が選択できるようにする
- マッスルの神様 = マ神 → 熨斗の王様 = のし王
ユーザー体験を最優先する
技術的な楽さを優先 ユーザー体験を優先 文字描画 ユーザー自身がWordなどで描画 Webサービス上で描画 仕上がり確認 プレビュー不可 or プレビューボタンクリックで表示 リアルタイムプレビュー表示 水引き、表書き ユーザーの選択したものを表示 用途を選ぶと最適な水引き、表書きを自動で選択 描画フォント 無料の範囲で選択可能 有料で質の良いフォントが選択可能 ユーザーが泥酔状態 酔いが冷めてから使う 泥酔状態でも直感で使える 仕様の実現方法を考える
- 使用した技術
- Webサービス上で文字描画しPDF出力
- 水引きの種類や表書きなどの情報をブラウザ上で選択させる
- サーバーでPDFを作成してダウンロードさせる(Golang/Google App Engine)
- リアルタイムプレビュー表示
- サムネイル描画サーバー(Golang/Google App Engine)を準備
- 水引きの種類や表書きなどの情報が変更されたらAjax(jQuery)でサーバーからサムネイル画像を取得し、ブラウザ上に即時反映
- 用途を選ぶと最適な水引き、表書きを自動で選択
- Bulma-ExtensionsのQuickViewで用途一覧を表示
- 用途を入力させて絞り込み(jQuery)
- 用途クリックで「水引き」と「表書き」を最適なものに変更(jQuery)
- 選定理由
- 仕様実現に際して最低限/シンプルなものを選ぶ
- 最新の技術よりも枯れて安定した技術を選ぶ
- なるべくメンテナンスが不要なものを選ぶ
- 投稿日:2019-10-01T17:40:30+09:00
Golang - Go Modulesで開発環境の用意する
はじめに
今まで以下の流れで開発環境を用意しました。
GoModulesの存在を知り、以下の理由からもう一度開発環境を見直すことにしました。
- バージョン管理のデファクトスタンダードになる(なってる?)GoModulesを理解したかった
- GoModulesを使用することで、設定に苦しんだGOPATH関連の制限から解放されそうだった
Go Modules
GoModulesは、Go1.11から導入され始めたGoの新しいバージョン管理システムになります。
詳細については、以下を参照いただくのが良いと思います。
GoModulesの概要から、今までのバージョン管理との違いまで把握できます。GOPATH mode から module-aware mode
今まで(GOPATH mode)は標準pkg以外を全部
$GOPATH
以下のディレクトリで管理する仕様となっており
プロジェクトも$GOPATH/src
配下に作成する必要がありました。この制約で上記の開発環境を用意する際にかなり苦しみました。しかし、module-aware mode では標準pkg以外の全てのパッケージをモジュールとして扱い、モジュールの管理やビルドが任意のディレクトリで可能になりました。($GOPATH/src にプロジェクトを配置しちゃダメというわけではなそう)
環境構築
go(1.10以降)とVSCodeはインストール済みの状態から始めたいと思います
私はgo(1.13.1)、VSCode(1.38.1)でやっています環境変数
.zshrc(Shellによる)export PATH=$GOPATH/bin:$PATH export GOPATH=$HOME/go export GO111MODULE=on※GOPATHはプロジェクトと違うディレクトリで試したかったので
$HOME/go
にしています
GO111MODULE
はGOPATH modeとmodule-aware modeを切り替えるための環境変数です。
Go 1.13からデフォルトがon
になる予定だったようですが、どうやらauto
がデフォルトになっているそうです。
そのため環境変数に上記を設定します。
on
:Go modules を使う (module-aware mode)off
:$GOPATH を使う (GOPATH mode)auto
:$GOPATH/src の外に対象のリポジトリがあり、 go.mod が存在する場合は module-aware mode、そうでない場合は GOPATH modeディレクトリの作成
以下の構成でディレクトリを作成します
$ tree -F GolangProjects GolangProjects └── github.com/ └── so-heee/ └── modules_example/モジュールの初期化
以下のコマンドでモジュールを初期化します
初期化するとgo.mod
ファイル(モジュールを管理するファイル)が出来ます$ go mod init github.com/so-hee/modules_example go: creating new go.mod: module github.com/so-hee/modules_example
└── modules_example └── go.modサンプルプログラムの作成
hello.gopackage main import ( "fmt" "rsc.io/quote" ) func main() { fmt.Println(quote.Hello()) }ビルドと実行
作成したファイルをビルドすると、依存パッケージである
rsc.io/quote
がダウンロードされます$ go build -o hello go: finding rsc.io/quote v1.5.2 go: downloading rsc.io/quote v1.5.2 go: extracting rsc.io/quote v1.5.2 go: downloading rsc.io/sampler v1.3.0 go: extracting rsc.io/sampler v1.3.0 go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: finding rsc.io/sampler v1.3.0 go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0cGOPATHに設定したディレクトリにパッケージがダウンロードされています
$ tree -F go -L 3 -d go └── pkg └── mod ├── cache ├── golang.org └── rsc.ioまた
go.sum
ファイル(依存モジュールのチェックサムの管理をしてるファイル)が作成されています
ビルドしたファイルを実行してみます$ ./hello Hello, world.
VSCodeでの環境設定
上記のフォルダをVSCodeで開きます
拡張機能インストール
Cmd + Shif + x でExtensionMarketplaceを開いてGoをインストール
先ほど作成したhello.goのファイルを開くとツールのパッケージをインストールするか聞かれるのでインストールしましょう
聞かれない場合がもしあった場合は、Cmd + Shift + P でコマンドパレットを表示
GO: Install/Update Tools
で全て選択してインストールしましょう独自パッケージの作成
新規でパッケージを作成し、mainでimportしてみます
modules_example/calc/calc.gopackage calc // Sum は引数a, bを合算して返却します func Sum(a, b int) int { return a + b }hello.gopackage main import ( "fmt" "github.com/so-heee/modules_example/calc" "rsc.io/quote" ) func main() { fmt.Println(quote.Hello()) fmt.Println(calc.Sum(1, 2)) }問題なくimportできたので、実行してみます。F5でデバッグしてみます
Hello, world. 3Dockerを使った開発環境の設定
dockerのインストール
Homebrewでdockerをインストールします(Homebrewの使い方は省略します)
$ brew cask install docker Updating Homebrew... ==> Auto-updated Homebrew! Updated 2 taps (homebrew/core and homebrew/cask). ==> Updated Formulae dbmate kops mosquitto rabbitmq ==> Satisfying dependencies ==> Downloading https://download.docker.com/mac/stable/38240/Docker.dmg ######################################################################## 100.0% ==> Verifying SHA-256 checksum for Cask 'docker'. ==> Installing Cask docker ==> Moving App 'Docker.app' to '/Applications/Docker.app'. ? docker was successfully installed! $ docker --version Docker version 19.03.2, build 6a30dfcVSCodeにRemote-Containersのインストール
Cmd + Shif + x でExtensionMarketplaceを開いて
Remote-Containers
を検索してインストールします設定ファイルの作成
左下の矢印アイコンを選択します
今度は
Remote-Containers: Add Development Container Configuration Files
を選択します
何の開発環境を作るか聞かれるためGo
を選択します選択すると先ほどのサンプルであった
.devcontainer
ディレクトリが作成され
その下にdevcontainer.json
とDockerfile
が入っていますDockerコンテナの作成
左下の矢印アイコンを選択します
Remote-Containers: Open Folder in Container
を選択し、フォルダを選択します
ビルドが開始されます
ビルド中にdetailsを押すと、ターミナルにビルドの状況が表示されます
完了するとエクスプローラーに表示されます
コンテナ上でGOのプログラムを実行
ターミナルタブを開いて、右側のプルダウンを
1:bash
にします
hello.goを実行してみますするとコンテナ上のGOPATH(devcontainer.jsonのgo:gopath)に依存パッケージがダウンロードされます
ローカルの時と同じですね。root@4f93101644d1:/workspaces/GolangProjects/github.com/so-heee/modules_example# go run ./hello.go go: downloading rsc.io/quote v1.5.2 go: extracting rsc.io/quote v1.5.2 go: downloading rsc.io/sampler v1.3.0 go: extracting rsc.io/sampler v1.3.0 go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: finding rsc.io/quote v1.5.2 go: finding rsc.io/sampler v1.3.0 go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c こんにちは世界。 3※こんにちは世界になるのは別の問題だと思うので今回は無視します(F5実行は問題ありません)
課題(依存先モジュールの編集する時)
githubで公開すると、基本的にそちらを参照してしまうため、ローカルで修正しても動作が変わりませんでした。。。
対応策としてgo.modを一時的に書き換えてreplaceディレクティブを使う方法や、go mod vendor でvendorを書き出してしまってそれを編集するなどがあるようですが、そもそも開発スタイルが正しいのか不安が残ります。
こちら解決策ご存知の方、もしくは別の方法をとってる方などいましたら是非ご教示ください!!参考:最近のGo Modulesプラクティス ~ ghqユーザーの場合も添えて
参考
- 投稿日:2019-10-01T03:24:37+09:00
Go言語版 競技プログラミング用標準入力関数を書いてみた
概要
fmt.scan
では、大量入力時に動作が遅いという事なので、入力数$10^5$に対応する関数を書いてみました。
バージョン 備考 対応バージョン 1.6以上 Scanner.Buffer
関数の対応バージョンAtCoder 1.6 2019年10月01日現在 Codeforces 1.12.6 2019年10月01日現在 基本的には、
Go 言語で標準入力から読み込む競技プログラミングのアレ --- 改訂第二版
の「bufio
のScanner
を使う (2) スペース区切りで読み込む」と同じですが、改良して長大文字列をScanner
で読めるようにします。
MaxScanTokenSize
の限界を突破するデフォルトの
Scanner
ではMaxScanTokenSize=65536
文字を超える文字列は読み込めなかったのですが、バージョン1.6でScanner.Buffer
関数が追加されました。この関数で使用するバッファと最大読み込み文字数を変更することができます。作成コード
import ( "os" "bufio" "strconv" ) const MaxBuf = 200100 var buf []byte = make([]byte,MaxBuf) var sc = bufio.NewScanner(os.Stdin) func init() { sc.Split(bufio.ScanWords) sc.Buffer(buf,MaxBuf) } func readString() string { sc.Scan() return sc.Text() } func readInt() int { sc.Scan() r,_ := strconv.Atoi(sc.Text()) return r } func readInt64() int64 { sc.Scan() r,_ := strconv.ParseInt(sc.Text(),10,64) return r } func readFloat64() float64 { sc.Scan() r,_ := strconv.ParseFloat(sc.Text(),64) return r }
func init()
は、func main()
の前に実行され、パッケージ変数で初期化できなかった処理を行います。
sc.Split(bufio.ScanWords)
- 空白文字区切りで文字列を読み込むよう設定します。
sc.Buffer(buf,MaxBuf)
- 前述の通り、読み込みバッファと最大サイズを変更します。
string
型の読み込み
sc.Scan()
で読み込んだ結果をそのまま返します。
int
型の読み込み
n := 1
と書くと、n
はint
型と型推論されます。int
型とint64
型の比較をしようとするとコンパイルエラーとなるため、整数は特に理由がない限りint
型として読み込みたいです。strconv.Atoi
関数を使用して文字列をint
型に変換します。競技プログラミングでは入力が欠落することがないため、エラー処理は行いません。
int64
型の読み込み
int
型のビット数は実装によって違うことがあるため、64ビット整数であることを保証するint64
型で読み込みたいことがあります。strconv.ParseInt
関数を使用します。
float64
型の読み込み
f := 3.14
と書くと、f
はfloat64
型と型推論されます。float32
型を使う理由は特にないため、float64
型の読み込み関数のみ用意します。strconv.ParseFloat
関数を使用します。