CSVファイル差分比較マニュアル
環境
やりたいこと
以下、CSVファイルの差分比較を行う手順と注意事項を書いていく。
比較対象のCSVファイルを整形する
- CSVファイルを比較可能な形に揃える作業
- 自分の経験上、業務でCSVファイルの比較を行う場合は何らかの前処理(余分な行・列の削除、ソート)が必要なことが多い
- シェルスクリプトで整形する
- 正直Excelでもできるが、Excelで編集した途端に日付、ダブルクォート、真偽値(true, false)が勝手に大文字になる、先頭の0が消滅する等何らかの災いが発生するので使わないほうが賢明と思う
ソート
$ sort
- 文字コード、辞書、数値を基準に昇順・降順のソートが可能
- ソート基準対象の列も指定できる
- 詳細は Man page of SORT
- sortコマンドについて詳しくまとめました 【Linuxコマンド集】
- ただし、DBから取得したデータ等でユニークキーが存在する場合は後述のcsvdiffを使えばソートは不要そう
補足
- カラムが多すぎてソートに指定したい列が何番目か分からなかったりする場合のワンライナー例
cat hoge.csv | head -n 1 | sed -e 's/,/\n/g' | nl 1 "都道府県コード" 2 "都道府県名" 3 "元号" 4 "和暦(年)"
文字コード変換
- Shift_JISだとターミナル上で日本語が文字化けする
# 文字コード判定 $ nkf -g hoge.csv Shift_JIS # UTF-8に変換(上書き) $ nkf --overwrite -w hoge.csv
実際に比較する
git diff
- こういうCSVファイルの場合
// test.csv "1","2","3","4","5" "6","7","8","9","10"
// test2.csv "1","2","3","4","5" "6","7","10","9","11"
- 比較する(2行目の3列目と5列目に差異)
$ git diff --word-diff-regex="[^[:space:],]+" test.csv test2.csv diff --git a/test.csv b/test2.csv index bbe528b..e69d468 100644 --- a/test.csv +++ b/test2.csv @@ -1,2 +1,2 @@ "1","2","3","4","5" "6","7"[-"8","9"-],"10",{+"9","11"+}
- 確かに差分比較できているが、上記のようなケースだと2行目3・5列目に差異があることが明確に視認できない(気がするのは自分だけ?)
csvdiff
- もっと良さげなのを探した
- 3列目と5列目に差異が発生していることが明確に分かる
csvdiff test.csv test2.csv -o word-diff # Additions (0) # Modifications (1) 6,7,[-8-]{+10+},9,[-10-]{+11+}
- また、このようにユニークキーを持つCSVファイルの場合は自動的にソート(比較行を選択)してくれる
// test3.csv aaa, 1, 2, 3, 4, 5 bbb, 6, 7, 8, 9, 10
// test4.csv bbb, 6, 7, 10, 9, 11 aaa, 1, 2, 3, 4, 5
$ csvdiff test.csv test2.csv -o word-diff -p 1 # Additions (0) # Modifications (1) bbb, 6, 7,[- 8-]{+ 10+}, 9,[- 10-]{+ 11+}
- 比較したい列番号が予め分かっている場合は、その列だけで比較判定できる
$ csvdiff test.csv test2.csv -o word-diff -p 0 --columns 2 # Additions (0) # Modifications (0)
まとめ
- csvdiff便利そう
Map型の変数の命名について考えた
Map型の変数
ふと、Map型の変数の名前の命名って何がベストなんだろうと気になったのでパターンをまとめてみた。
ハンガリアン記法パターン
とりあえず変数名の末尾にMapをつけておくパターン。 例えば、社員コードと社員名の対応付けを格納するMapの場合はこんな感じだろうか。
var empCodeMap = new Map(); empCodeMap.set('123', '太郎'); empCodeMap.get('123');
型宣言が不要な言語の場合は命名の選択肢としてはアリかもしれない。 そうでないならあまり選択するメリットがないと思う。
KeyToValueパターン
キーと対応する値を変数名に含めるパターン。 シンプルで情報量が多いのが利点。私はいつもこの命名パターンを利用してMap型の変数を宣言する。
var empCodeToName = new Map(); empCodeToName.set('123', '太郎'); empCodeToName.get('123');
valueByKeyパターン
値を変数名の先頭に持ってきてキーを後に続けるパターン。 KeyToValueパターンと情報量は変わらないので好みの問題?
var nameByEmpCode = new Map(); nameByEmpCode.set('123', '太郎'); nameByEmpCode.get('123');
valueOfパターン
言語の構文によっては前置詞が自然に繋がるので良いのかもしれない。 例えばJavaScriptやJavaだと不自然な上に情報量が減るので悪い命名だと思う。
var empCodeOf = new Map(); empCodeOf.set('123', '太郎'); empCodeOf.get('123');
参考
「プロを目指す人のためのRuby入門」を読んでRubyに入門した感想
プロを目指す人のためのRuby入門
自分のスキル
- エンジニア業務歴2年ぐらい
- いわゆるスクリプト言語、コンパイル言語は両方経験ある(主にJavaScript, Apex(Java)等)
- プログラミング自体は学生時代含めて6年前後はやってる
- Rubyほぼ知らない
感想
本の感想というよりはRubyを初めて学んで感じたことをジャンル別に整理してみた。
驚き
(少なくとも自分は)他の言語で見たことがない規則や構文
- 変数を宣言するだけの構文はない
- 末尾が?のメソッド名は返り値が真偽値、末尾が!は副作用ありを示す慣習
- メソッド内で最後に評価された式が戻り値になる
- メソッド宣言時や呼び出し時に引数のカッコを省略可能
- ifの反対の意味を持つunless
- シンボルの概念(JavaのEnumと同じな気もする)
- ifの条件式でローカル変数に代入
- privateメソッドはレシーバーを指定できないという定義
- aliasキーワード(便利に見えるけど混乱するだけな気もする)
- クラスにアクセス修飾子が使えない
JavaScriptにも欲しい
JavaScriptとは違う
- メソッド呼び出し時の引数の過不足はエラー
- ブロックの概念(クロージャ)
- 範囲オブジェクトがある
JavaScriptと似ている
- 後付で何でも修正できる
忘れそう・難しい
- 引数の最後がハッシュならハッシュリテラルの{}を省略可能
- メソッド宣言時の引数の種類と並び順
- Proc.newとラムダの違い
- 二重コロンでモジュール内のクラス、クラス内の定数参照
例外クラスについて
(プロを目指す人のためのRuby入門 図9-3より引用)
総括
- (慣れの問題とは思うが)Rubyは省略記法や構文が独特かつ自由な印象があってすぐに忘れそう
- その分他の言語と比べると、表現したいことに対してコードの量は少なく済むので慣れている人は書きやすいし読みやすいのかも
- 静的型付がないので、コードの品質を保てないまま規模が大きくなると非常に辛そう(JavaScriptと同様な感じになる)
次はRails
Rules of Hooksに違反していないのにHooks can only be called inside the body of a function componentエラーにハマった(と思った)話
環境
- react 16.8.2
- webpack 4.29.3
事象
- webpack-dev-sereverで、Hooksを利用した下記のコードを実行すると
Hooks can only be called inside the body of a function component
エラーが発生
再現手順
- 問題のコード(イメージ)
// ./App/index.tsx import * as React from 'react'; const App = () => { const hooks = React.useState('hoge'); return <span>hoge</span>; }; export default App;
// ./index.tsx import * as React from 'react'; import * as ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));
<!-- ./index.html --> <html> <body> <div id="root"></div> <script src="bundle.js"></script> </body> </html>
webpack-dev-serverを利用してindex.htmlを開くと
Uncaught Invariant Violation: Hooks can only be called inside the body of a function component
エラー- 単純にビルドだけして開いてみたら発生しなかった(webpack-dev-serverが怪しい...?)
エラー自体はHooksの呼び出し位置が適切できないといった内容のようだが、この場合は特にそんなことはない(詳細はRules of Hooks参照)
- こんなシンプルな構成なのになんで? 何が起きてる?
HtmlWebpackPluginのhtmlテンプレートが原因
- 自分の環境ではwebpack-dev-serverを利用する際に HtmlWebpackPluginを使って動的にhtmlファイルを出力していた
- なので、上記のindex.htmlをそのまま利用しているわけではなく、htmlテンプレートとして使っていた
- おもむろにindex.htmlをブラウザで開いてみたら...
<html> <body> <div id="root"></div> <script src="bundle.js"></script> <script src="bundle.js"></script> </body> </html>
このようにバンドルされたjsファイルへの参照が自動挿入されて2つになっていた
- (webpack-dev-serverを利用しない時は上記のhtmlを使用しないので再現しなかった)
ひとまずhtmlテンプレートを修正したらエラーを吐かなくなって一安心
ReactDOM.renderを2回呼び出すとどうなるか
If the React element was previously rendered into container, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element.
ReactDOM – Reactより引用
- ただしFunction Componentのrenderメソッド相当(返り値)以外の部分は普通に実行されるので
React.useState('hoge')
が2度評価されたことが原因っぽいなあと予想 - しかし、ReactDOM.renderを2回続けて呼び出すコードを実行しても再現しなかった
- ReactDOM.renderというよりbundle.jsを2回読み込んでいることが影響しているのかも
- Hooks使わないコードだとエラーが発生しないので今までhtmlテンプレートに問題があることに気づけなかった...
VSCodeでTypeScriptを書くときに役立った拡張機能まとめ
1~2週間ほどVSCodeでTypeScript(+React)を書いていたので、その際に役に立った拡張機能をまとめ。
環境
TypeScript Importer
- TypeScript Importer - Visual Studio Marketplace
- 未インポートのモジュールを利用してコードを書き始めると自動的にインポートの宣言文を挿入してくれる
- ただし、たまに意図しない動作をしたり、あるいは動作を期待していたら動作しなかったりすることがある気がする
- VSCodeのコマンドパレットからAdd Importを実行すると、インポートするモジュールを選べる
- 自分でインポートの宣言文を書く気にはなれないのでこれがけっこう便利
TypeScript Import Sorter
- TypeScript Import Sorter - Visual Studio Marketplace
- VSCodeのコマンドパレットからSort Importsを実行して、インポートの宣言文をソートできる
- 設定すればファイル保存時に自動的ソートすることもできて便利(
"importSorter.generalConfiguration.sortOnBeforeSave": true
)
Move TS
- Move TS - Move TypeScript files and update relative imports - Visual Studio Marketplace
- ファイルを移動した際に影響するインポート宣言文のファイルパスを自動的に書き換えてくれる
- 自分で定義したモジュールのインポート宣言文は相対パスで書く場合が多いと思うが、インポート対象として参照が多いファイルを移動したくなった際に手作業で書き換えるのは辛いので助かる
- 書いていて気になったので調べたけど、そもそも絶対パスで記述するという手もあるみたい(絶対パスでモジュールをimportする - Qiita )
Prettier
- Prettier - Code formatter - Visual Studio Marketplace
- コード整形。使ってみると、これなしの開発は考えられなくなる
- 自分は元々使っていて、TypeScriptファイル保存時にもPrettierが自動的に実行されるように設定した
ES7 React/Redux/GraphQL/React-Native snippets
- ES7 React/Redux/GraphQL/React-Native snippets - Visual Studio Marketplace
.ts
と.tsx
ファイルでも動作するスニペット集- 拡張の名前にはReact/Redux/GraphQL/React-Nativeと様々なものが含まれているが、自分が使うのは単純なJavaScriptの構文がほとんど(全部覚えられない)
- よく使うのは
exp
=export default moduleName
とかエクスポート宣言文系
- よく使うのは
その他
- lintについては、今後はTSLintではなくESLintがTypeScript対応を進めるという発表があり( TypeScript Roadmap: January - June 2019 · Issue #29288 · Microsoft/TypeScript · GitHub)しばらくは手を出さなくていいかなと思ってる
- 自分は、ES5のコードベースでもPrettierを使うならESLintは
no-unused-var
とかno-unreachable
ぐらいで十分だと思っていて、TypeScriptについてはVSCodeが最低限の警告を出してくれる(no-unreachable
は警告してくれないみたいだけど)のであまり困っていないというのもある
まとめ
- そういうわけでTypeScript書いていきましょう
"Java 8 is required to run..."エラーが表示されVSCodeでApexのシンボル情報を参照できなくなった場合の対応
環境
事象
なぜかVSCodeでApexのシンボル情報を参照できなくなった(とても開発効率が落ちる)
- ↓これが出なくなった
- ついでにサイドバーのアウトラインも表示されなくなった
VSCode起動時に
Java 8 is required to run. Download and install it from https://java.com/en/download/.
というエラーが表示されるようになった
Java11が原因?
forcedotcom/salesforcedx-vscodeにissueが起票されていた
github.com
- Apex Language Server · forcedotcom/salesforcedx-vscode Wiki · GitHubに書いている通りにsalesforcedx-vscode-apex.java.home
にJava8用のパスを設定したら直った
$ java --version
したらJava11.0.2だった- VSCode拡張のApexはJava8のみ対応とのことだった
- 特に環境を更新した記憶はないけど、知らない内にJava11がインストールされていた...?
文字からUTF-8のバイトコードを調べるワンライナー
環境
文字からUTF-8のバイトコードを調べるワンライナー
ー
(全角ハイフン)を調べたい場合
$ echo -n 'ー' | iconv -f utf-8 | xxd -p e383bc
-t
を明示しない場合はUTF-8で出力と解釈される
ワンライナーの意味
- 下記を参照
出力するエンコーディング方式を指定する
-
xxd
はファイルのダンプなのでUTF-16BEのBOMfeff
も付与されている模様(30fc
がー
のバイトコード)
$ echo -n 'ー' | iconv -f utf-8 -t utf-16 | xxd -p feff30fc
$ echo -n 'ー' | iconv -f utf-8 -t sjis | xxd -p 815b
他の方法は
- あるかもしれないです