Corredor

ウェブ、プログラミングの勉強メモ。

CSS だけでテキストを虹色のグラデーションでアニメーションさせる

Webポートフォリオ・デザインブック SNS時代のクリエイティブの見せ方・伝え方

Webポートフォリオ・デザインブック SNS時代のクリエイティブの見せ方・伝え方

  • 作者: 小島幸代,草野恵子,北川貴清,久保靖資
  • 出版社/メーカー: エムディエヌコーポレーション
  • 発売日: 2018/02/27
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

ある文字列全体の color がアニメーションで変化するのではなくて、linear-gradient() で作ったグラデーションを文字色として適用し、それをアニメーションさせる。

説明がよく分からないと思うので、以下の CodePen で実物を見て欲しい。

See the Pen Rainbow Animation Text by Neos21 (@Neos21) on CodePen.

こんな風になる。

グラデーションさせる文字列は span など任意のインライン要素で囲んでしまって良い。幅指定なども不要。

サンプルは虹色にグラデーションするように作ったが、始点と終点の色さえ合わせておけばリニアにループできるので、どんなグラデーションにしても問題ないだろう。

以下 CSS コード。

.example {
  /* フォントサイズなどを任意で指定する */
  font: bold 10em / 1 Verdana, Helvetica, Arial, sans-serif;
  text-transform: uppercase;
  
  /* 背景グラデーションを指定・幅を 200% にしておく */
  background: linear-gradient(to right, #f00 0%, #f80 14.28%, #dd0 28.56%, #0d0 42.85%, #0dd 57.14%, #00f 71.42%, #e0e 85.71%, #f00 100%) 0% center / 200% auto;
  
  /* 背景画像を文字でマスクする */
          background-clip: text;
  -webkit-background-clip: text;
  
  /* 文字色を透明にできればよく color: transparent でも color: rgba(0, 0, 0, 0) でも可 */
          text-fill-color: transparent;
  -webkit-text-fill-color: transparent;
  
  /* アニメーション指定 */
  animation: example 4s linear infinite;
}

/* 背景の横位置をズラす */
@keyframes example {
  to { background-position-x: 200%; }
}

background をテキストでマスクするには、-webkit-background-clip: text というプロパティで制御できる。background-clip: text の方はまだ仕様外だと思われるが、一応指定。

文字色を透過させるには、-webkit-text-fill-color: transparent を使ったが、文字色を透明にできれば良いので、color: transparent でも、color: rgba(0, 0, 0, 0) でも大丈夫だった。コレで背景のマスクが出来た。

続いて背景のグラデーションを指定するワケだが、ポイントは background-size で幅を 200% に指定しておくこと。コレがないと background-position (-x) でパーセント指定した時にアニメーションしないのである。

上述のサンプルコードは background プロパティにまとめて書いてしまっているが、まとめる必要がなければ background-position の始点に関する指定は不要。

最後に background-position-x をズラすアニメーションを定義して無限ループさせれば OK。

これでちょっとした演出ができるかと。

はてなブログの Amazon と楽天の商品リンクにアイコンを付けた 第2弾

はてなブログの Amazon 商品リンク枠と、楽天商品リンク枠に、それぞれのサービスのロゴを表示させるカスタマイズ、第2弾。

経緯

以前、こんな記事を書いた。

neos21.hatenablog.com

はてなブログにおける、Amazon や楽天の商品リンクの右下にそれぞれのサービスのロゴを配置しよう、というもの。このカスタマイズを行うと、デフォルトでは「Amazon 商品リンク」なのか「楽天商品リンク」なのかの区別が付きづらいところ、一目で区別が付くようになる。

f:id:neos21:20180325150241p:plain

↑コレが以前の記事で紹介したアイコンのサンプル。

この時のサンプルは背景画像に Data URL を埋め込んでおり、「CSS のみで実装」とは書いていたが、実質的には画像を組み合わせて作っていた。

発展版を作成した

今回作った発展版は、はてなブログにデフォルトで組み込まれている blog.css の中に含まれる「BlogIcon」フォントを利用している。よって、新たに画像を用意することなく実装しており、コード量も減らせている。

動作サンプル

実はもうこのブログには発展版を適用してある。商品リンクが以下のキャプチャのように表示されているはずだ。以前のサンプルと見た目はほぼ変わらない。

f:id:neos21:20180325154145p:plain

以下の CodePen に、旧サンプルとの比較ができるモノを作った。コチラもご覧いただきたい。

See the Pen Hatena Blog Amazon Rakuten Icon by Neos21 (@Neos21) on CodePen.

CSS コードを公開

コードは CodePen に載せているモノのとおり。繰り返しになるが、このコードを動作させるには、はてなブログが提供する blog.css を読み込んでいることが前提となる。

/* Amazon・楽天 共通 : 基準設定 */
.hatena-asin-detail {
  position: relative;
  border-radius: 4px;
}

/* Amazon・楽天 共通 : 右下に余白を開けコンテンツを配置する準備をしておく */
.hatena-asin-detail::before {
  position: absolute;
  right: .6rem;
  bottom: .6rem;
  font-size: 55px;
  font-family: blogicon;  /* blog.css で読み込まれる blogicon フォントを利用する */
  line-height: 1;
}

/* Amazon : 円形グラデーションで色を分けマスクすることで「a」部分を黒色・矢印を黄色にする */
.hatena-asin-detail:not(.hatena-rakuten-detail)::before {
  content: "\f034";  /* Amazon アイコン */
  color: transparent;
  background: radial-gradient(ellipse farthest-corner at 50% 20px, rgba(0, 0, 0, .5) 50%, rgba(255, 153, 0, .5) 50%) 50% 50% / 60px 50px no-repeat;
          background-clip: text;
  -webkit-background-clip: text;
}

/* 楽天 : アイコンに合わせて白い円を作り、透過されている「R」部分を白色にする */
.hatena-asin-detail.hatena-rakuten-detail::before {
  content: "\f722";  /* 楽天アイコン */
  border-radius: 50%;
  width: 48px;
  height: 47px;
  line-height: 42px;
  color: rgba(200, 0, 0, .5);
  background: rgba(255, 255, 255, .5);
}


/* ==============================
 * Amazon : IE11 用 Polyfill
 * ============================== */

/* IE11 だと background-clip が効かないため、黄色ベースでアイコンを置いておく・この上に黒色の「a」部分を半透明で重ねる */
_:-ms-lang(x)::-ms-backdrop, .hatena-asin-detail:not(.hatena-rakuten-detail)::before {
  color: rgba(255, 153, 0, .5);
  background: none;
}

/* .hatena-asin-detail-foot は空の要素・黒色の「a」部分をクロップするため幅・高さを指定して配置する */
_:-ms-lang(x)::-ms-backdrop, .hatena-asin-detail:not(.hatena-rakuten-detail) .hatena-asin-detail-foot {
  position: absolute;
  right: calc(9px + .6rem);
  bottom: calc(15px + .6rem);
  width: 32px;
  height: 40px;
  line-height: 1;
  overflow: hidden;
}

/* .hatena-asin-detail-foot の疑似要素でアイコンを配置し、「a」部分の左側の余白を削る */
_:-ms-lang(x)::-ms-backdrop, .hatena-asin-detail:not(.hatena-rakuten-detail) .hatena-asin-detail-foot::before {
  content: "\f034";  /* Amazon アイコン */
  position: absolute;
  left: -5px;
  color: rgba(0, 0, 0, .6);
  font-size: 55px;
  font-family: blogicon;
}

IE11 向けの Polyfill が3ブロックほど最後にまとまっているが、IE11 を無視して良ければ実にシンプル。

実装詳細

以下、実装の詳細を紹介する。

Amazon アイコンの作り方

Amazon のアイコンは、BlogIcon フォントで \f034 文字を指定すると表示できる。Unicode の U+E000 から U+F8FF は私用領域、つまり「好きに使ってね」という領域で開けられており、その中の文字に Amazon アイコンが当てられている。

通常どおりアイコンとして利用する場合は、以下のように使う。

<i class="blogicon-amazon"></i>

コレで、次のように表示される → (サンプルのため文字サイズを大きくした)

この文字を擬似要素で配置しているワケだが、問題は文字色。Amazon のロゴアイコンは、「a」部分が黒色、下の矢印部分が黄色 (#ff9900) である。

単純に color で文字色を指定してしまうと、「a」部分も「矢印」部分も同色になってしまうため、どうにかして「矢印部分だけ黄色」にしたかった。

最初は「::before 疑似要素と ::after 疑似要素を組み合わせて1つのロゴを作ろうか…」と試行錯誤していたが、overflow: hidden によるクロップが限界で断念。そして辿り着いたのは、-webkit-background-clip: text を使い、背景指定を文字列でマスク表示させる方法だった。radial-gradient で円形のグラデーションを作り、「a」部分だけを丸く囲んで黒色を当て、グラデーションする範囲を作らずすぐに外周に黄色を当てるようにした。

f:id:neos21:20180325160110p:plain

-webkit-background-clip: text 指定を外すと、こんな風に見える。

こうして1文字に2色の文字色を付けられた。

IE11 は background-clip: text が効かない

せっかく頑張って作ったのだが、IE11 は background-clip: text に対応しておらず、マスク化ができなかった。

そこで、当初考えていた ::before 疑似要素と ::after 疑似要素を組み合わせる方法に戻り、なんとかならないか挑戦してみたのだが、IE11 は overflow: hidden を指定して border-radius で要素を丸めた時、はみ出た部分にも文字がはみ出て表示されてしまい、うまくクロップできなかった。

試行錯誤したが、IE11 の場合は残念ながら、苦肉の策で半透明の黄色ベースでアイコン全体を配置し、その上に「a」部分のみを上手くクロップした要素を重ねることにした。そのため、IE11 で見た時だけ「a」部分が若干黄ばんでいる…。

f:id:neos21:20180325163005p:plain

IE11 のみ CSS を適用する CSS ハックは以下で紹介したモノを使用した。

neos21.hatenablog.com

楽天アイコンの作り方

楽天アイコンの場合は Amazon アイコンよりは簡単だったが、一つ拘ったところがある。

まずは通常のアイコンを表示させてみる。文字コードとしては \f722 で表示できる。

<i class="blogicon-rakuten"></i>

コレで、次のように表示される → (サンプルのため文字サイズを大きくした)

楽天アイコンの場合、丸い囲み部分に色が付いており、中央の「R」部分は透過されている。円の部分に色を付けるのは color プロパティで良いのだが、このままだと「R」部分は透明なので、このアイコン部分に文字が重なった時に、重なった文字が薄く表示されないのである。また、商品リンク枠全体に白以外の背景色が付いた時も、不格好なのである。

f:id:neos21:20180325163842p:plain

↑「R」部分の後ろに見える「あ」の文字が通常の濃さで見えている上に、背景色が白色以外だと「R」字がその色になってしまう。

そこで、border-radius: 50% で円を作り、白色の背景色を付けることで、白い円の土台に丸文字を重ねた状態を作った。

f:id:neos21:20180325164326p:plain

完璧には縁取り出来ていないので、若干ハミ出す感もあるが、ご愛嬌…。基本は白背景で使ってもらう想定なので…。

コレで、「R」字部分に重なる文字があっても、半透明で表示されることになる。

コードの縮減率は…?

さて、今回のサンプルでどのくらいコード量が減らせたか、圧縮したコード同士で比較してみよう。

/* 前回の旧サンプル : 1957文字 */
.hatena-asin-detail{border-radius:4px;background:linear-gradient(to right,rgba(255,255,255,.2),rgba(255,255,255,.2)),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAACkElEQVRoge2YybGjMBCGOwRCIARdbHHUxRYn6BAcgjMgBEJwCFRZfmdCIARCIISeg9ozeJEMBci8GrqqTyD4P/WiBWCzzTbb7G5CYbQ/ZoXU+UXqvJY6b6TOO6nzVuq8ss/wLBRG39b6YEmKSuqsZLE00KtVgEiN5xGin71LUlS/VXwfIv6t4u/efgEgb2YEoKBRsEXrFVTvDiiEwihJMR4Srf0xK4IBcJt0iMlKB/TpU1cKCdCOLUihMFpNHeyPiPLfYtWHufjGecBJ6rwLpf+tCYXRp4Vp1QBDbNUAdh+EyFuKmttsy971fF0AtjhH74PWAcD9farw7wDMvJUIC8Bt1DfzrdRZmaR42h1QJCnGA9aBcABcpC4htaudrgKAZ98lwntIWQUAd5y3IvZHRNe43QHFSgDyyiXCtyUeUvShANqxAFzAvrr5OAFzAjiFuPb0vrR7dDwHAPgkxl6bCIWRzfuh4m0dLB6FBRawlza8KMCAbjLZA0TBd6T0pwjf3Pne8R6KZjHuKs5u5BZv1wn3+Tgrg93WMcTQSNS7A4r+ePm4nnRBOtA7ezofs5i8kzpv9seseBbeNx7TJSmeAkpe1qiCiAwUZKAhAx0ZILpBSwaG3xuRgZpu8PZ+Z2mjG1zYS7pBSQaqO8TYD5U88CsgD1psNJrxA69wIgPEXpEB525zLiMDqpdCDQDA6BR6+OAPCP4Y/XUbHUUVTG55nPPYE33/T00/IPj/RD/gbAbDfnSFE88EPXnH0Sk4YorhYvaIKohZCPI7BRmoXybGetOPNBkoZk1jusLZATLVa7rC+TmqdIPLHJF+BbmHfRpMQwaKyekxGaaCmCNz4dSoe2Ade0MGKq4fXGRWN9vsP7Q/PeTs283e6DMAAAAASUVORK5CYII=") no-repeat right 10px bottom 10px/48px 48px}.hatena-asin-detail.hatena-rakuten-detail{background:linear-gradient(to right,rgba(255,255,255,.5),rgba(255, 255,255,.5)),url("data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MC41OCA1MS4wNiI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNiZjAwMDA7fS5jbHMtMntmaWxsOiNmZmY7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZT7jgqLjg7zjg4jjg5zjg7zjg4kgMTwvdGl0bGU+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNTAuNTgsMjUuNzhBMjUuMjksMjUuMjksMCwxLDEsMjUuMjkuNDgsMjUuMjksMjUuMjksMCwwLDEsNTAuNTgsMjUuNzhaIi8+PHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMjEuOTQsMzkuMzZWMzAuOTNIMjUuNmw2LjMyLDguNDNoNi40N0wzMC43NSwyOS4xOWE5LjM3LDkuMzcsMCwwLDAtNS40My0xN0gxNi43OFYzOS4zNmg1LjE2Wm0wLTIyaDMuMzdhNC4yMSw0LjIxLDAsMSwxLDAsOC40M0gyMS45NFoiLz48L3N2Zz4=") no-repeat right 10px bottom 10px/48px 48px}

/* 今回の新サンプル : 1186文字 */
.hatena-asin-detail{position:relative;border-radius:4px}.hatena-asin-detail::before{position:absolute;right:.6rem;bottom:.6rem;font-size:55px;font-family:blogicon;line-height:1}.hatena-asin-detail:not(.hatena-rakuten-detail)::before{content:"\f034";color:transparent;background:radial-gradient(ellipse farthest-corner at 50% 20px,rgba(0,0,0,.5) 50%,rgba(255,153,0,.5) 50%) 50% 50% / 60px 50px no-repeat;background-clip:text;-webkit-background-clip:text}_:-ms-lang(x)::-ms-backdrop,.hatena-asin-detail:not(.hatena-rakuten-detail)::before{color:rgba(255,153,0,.5);background:0}_:-ms-lang(x)::-ms-backdrop,.hatena-asin-detail:not(.hatena-rakuten-detail) .hatena-asin-detail-foot{position:absolute;right:calc(9px + .6rem);bottom:calc(15px + .6rem);width:32px;height:40px;line-height:1;overflow:hidden}_:-ms-lang(x)::-ms-backdrop,.hatena-asin-detail:not(.hatena-rakuten-detail) .hatena-asin-detail-foot::before{content:"\f034";position:absolute;left:-5px;color:rgba(0,0,0,.6);font-size:55px;font-family:blogicon}.hatena-asin-detail.hatena-rakuten-detail::before{content:"\f722";border-radius:50%;width:48px;height:47px;line-height:42px;color:rgba(200,0,0,.5);background:rgba(255,255,255,.5)}

/* 今回の新サンプル … IE11 で Amazon を「黄色一色」にしたら : 754文字 */
.hatena-asin-detail{position:relative;border-radius:4px}.hatena-asin-detail::before{position:absolute;right:.6rem;bottom:.6rem;font-size:55px;font-family:blogicon;line-height:1}.hatena-asin-detail:not(.hatena-rakuten-detail)::before{content:"\f034";color:transparent;background:radial-gradient(ellipse farthest-corner at 50% 20px,rgba(0,0,0,.5) 50%,rgba(255,153,0,.5) 50%) 50% 50% / 60px 50px no-repeat;background-clip:text;-webkit-background-clip:text}_:-ms-lang(x)::-ms-backdrop,.hatena-asin-detail:not(.hatena-rakuten-detail)::before{color:rgba(255,153,0,.5);background:0}.hatena-asin-detail.hatena-rakuten-detail::before{content:"\f722";border-radius:50%;width:48px;height:47px;line-height:42px;color:rgba(200,0,0,.5);background:rgba(255,255,255,.5)}

旧サンプルは Data URL 文字列がかさんで1957文字。それに対し、今回の新サンプルでは1186文字と、771文字 (バイト) 削減できた。さらに、IE11 で Amazon ロゴの2色表示を諦め、「黄色一色」にしてみたとしたら、.hatena-asin-detail-foot 要素への指定が削れるので754文字になる。これなら1203文字、約 1.2kb も削減できており、CSS のサイズ縮小に貢献できたであろう。

はてなブログカスタマイズガイド―HTML & CSSで「はてなブログ」を次のステッ

はてなブログカスタマイズガイド―HTML & CSSで「はてなブログ」を次のステッ

コマンドラインで文字コードや改行コードを調べる方法まとめ

コマンドラインで文字コードや改行コードを判定したく、やり方を調べた。Windows と Mac でそれぞれやり方に微妙な差異があったので、それぞれ検証してみた。

今回の目標

今回は、コマンドラインで文字コードや改行コードを判定したいと考えているが、その際検証したい内容は以下のとおり。

  • カレントディレクトリ配下のすべてのファイルを対象に検索したい
  • 文字コード :
    • BOM なし UTF-8 になっていないモノを知りたいので、Shift-JIS や EUC-JP なファイルを検出したい
    • BOM 付き UTF-8 は BOM なし UTF-8 と別に検出したい
  • 改行コード :
    • LF に統一したいので、CR が含まれるファイル、CRLF で改行しているファイルを検出したい

検証に使用するファイル

検証に用意したファイルの内容は以下のとおり。いずれも VSCode の機能を利用して、文字コードと改行コードを設定した。

文字コード 改行コード 内容 注釈
UTF-8 (BOM なし) LF 英文のみ ASCII 扱いされる場合あり
UTF-8 (BOM なし) LF 含日本語 -
UTF-8 (BOM なし) CR+LF 英文のみ ASCII 扱いされる場合あり
UTF-8 (BOM なし) CR+LF 含日本語 -
UTF-8 (BOM アリ) LF 英文のみ -
UTF-8 (BOM アリ) LF 含日本語 -
UTF-8 (BOM アリ) CR+LF 英文のみ -
UTF-8 (BOM アリ) CR+LF 含日本語 -
Shift-JIS LF 英文のみ ASCII 扱い
Shift-JIS LF 含日本語 -
Shift-JIS CR+LF 英文のみ ASCII 扱い
Shift-JIS CR+LF 含日本語 -
EUC-JP LF 英文のみ ASCII 扱い
EUC-JP LF 含日本語 -
EUC-JP CR+LF 英文のみ ASCII 扱い
EUC-JP CR+LF 含日本語 -

文字コードの基礎のおさらいとなるが、UTF-8・Shift-JIS・EUC-JP など大抵の文字コードは ASCII から拡張しているエンコード体系であり、これらのファイルには BOM が付いていないため、ASCII の範囲内の文字 (= アルファベット程度) しか出てこない場合は「文字エンコーディング」という概念が発生しないのだ。

世界中で使用されている様々な文字の符号化方式の多くは、ASCIIで使用されていない128番以降の部分に、その他の文字を割り当てたものである。

だから、エディタで Shift-JIS エンコードを指定して保存したとしても、アルファベットしか含んでいないファイルだった場合は、次開いたときには「UTF-8」なり「ASCII」なりに自動判定されることになる。ココはエディタが「(BOM なし) UTF-8」と表現するか、「ASCII」と表現するかの違いであり、エンコーディングの対象となる文字列が登場していない以上はそのテキストファイルの文字コードは未確定なのだ。

BOM 付き UTF-8 の場合は別で、ASCII の範囲の文字しか登場していなくても「BOM 付き UTF-8」と判定できる。バイト・オーダー・マークのおかげである。

Mac での調べ方

Mac での調べ方アレコレ。

file コマンド

標準コマンドである file コマンドを使うと、自然な表現でテキストファイルの内容を示してくれる。

$ file ./*
./EUC-JP - CRLF - EN.txt:    ASCII text, with CRLF line terminators
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./EUC-JP - LF - EN.txt:      ASCII text
./EUC-JP - LF - JP.txt:      ISO-8859 text
./Shift-JIS - CRLF - EN.txt: ASCII text, with CRLF line terminators
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./Shift-JIS - LF - EN.txt:   ASCII text
./Shift-JIS - LF - JP.txt:   Non-ISO extended-ASCII text
./UTF-8 - CRLF - EN.txt:     ASCII text, with CRLF line terminators
./UTF-8 - CRLF - JP.txt:     UTF-8 Unicode text, with CRLF line terminators
./UTF-8 - LF - EN.txt:       ASCII text
./UTF-8 - LF - JP.txt:       UTF-8 Unicode text
./UTF-8 BOM - CRLF - EN.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - CRLF - JP.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - LF - EN.txt:   UTF-8 Unicode (with BOM) text
./UTF-8 BOM - LF - JP.txt:   UTF-8 Unicode (with BOM) text
  • 文字コード
    • BOM 付き UTF-8 は判定できている。file ./* | grep "(with BOM)" で BOM 付きのファイルのみ特定などはできそう。
    • Shift-JIS の判定ができてない。
    • EUC-JP は ISO-8859 と判定された。
  • 改行コード
    • CRLF のファイルのみ表記され、LF の場合は未表記。file ./* | grep "with CRLF" で CRLF な改行コードのファイルは特定できそう。

nkf

次に、前回紹介した nkf を使った場合。nkf は --guess-g オプションで指定したファイルの文字コードや改行コードを判定できる。

Mac 版 nkf の場合、-g だと文字コードのみの判定になってしまうので、改行コードもチェックするには --guess を指定する必要があることに注意。

実行結果は以下のとおり。

$ nkf --guess ./*
./EUC-JP - CRLF - EN.txt: ASCII (CRLF)
./EUC-JP - CRLF - JP.txt: EUC-JP (CRLF)
./EUC-JP - LF - EN.txt: ASCII (LF)
./EUC-JP - LF - JP.txt: EUC-JP (LF)
./Shift-JIS - CRLF - EN.txt: ASCII (CRLF)
./Shift-JIS - CRLF - JP.txt: Shift_JIS (CRLF)
./Shift-JIS - LF - EN.txt: ASCII (LF)
./Shift-JIS - LF - JP.txt: Shift_JIS (LF)
./UTF-8 - CRLF - EN.txt: ASCII (CRLF)
./UTF-8 - CRLF - JP.txt: UTF-8 (CRLF)
./UTF-8 - LF - EN.txt: ASCII (LF)
./UTF-8 - LF - JP.txt: UTF-8 (LF)
./UTF-8 BOM - CRLF - EN.txt: UTF-8 (BOM) (CRLF)
./UTF-8 BOM - CRLF - JP.txt: UTF-8 (BOM) (CRLF)
./UTF-8 BOM - LF - EN.txt: UTF-8 (BOM) (LF)
./UTF-8 BOM - LF - JP.txt: UTF-8 (BOM) (LF)

# ちなみに -g オプションだとこうなる
$ nkf -g ./*
./EUC-JP - CRLF - EN.txt: ASCII
./EUC-JP - CRLF - JP.txt: EUC-JP
./EUC-JP - LF - EN.txt: ASCII
./EUC-JP - LF - JP.txt: EUC-JP
./Shift-JIS - CRLF - EN.txt: ASCII
./Shift-JIS - CRLF - JP.txt: Shift_JIS
./Shift-JIS - LF - EN.txt: ASCII
./Shift-JIS - LF - JP.txt: Shift_JIS
./UTF-8 - CRLF - EN.txt: ASCII
./UTF-8 - CRLF - JP.txt: UTF-8
./UTF-8 - LF - EN.txt: ASCII
./UTF-8 - LF - JP.txt: UTF-8
./UTF-8 BOM - CRLF - EN.txt: UTF-8
./UTF-8 BOM - CRLF - JP.txt: UTF-8
./UTF-8 BOM - LF - EN.txt: UTF-8
./UTF-8 BOM - LF - JP.txt: UTF-8
  • 文字コード
    • Shift-JIS・EUC-JP の判定は完璧。
    • UTF-8 の BOM についても --guess オプションの方で分かる
  • 改行コード
    • -g ではなく --guess オプションならきちんと調べられる

od コマンド

改行コードを調べるのに od コマンドが使える。

# -c オプション
$ od -c 'UTF-8 - CRLF - EN.txt'
0000000    U   T   F   -   8  \r  \n   C   R   L   F
0000013

# -a オプション
$ od -a 'UTF-8 - CRLF - EN.txt'
0000000    U   T   F   -   8  cr  nl   C   R   L   F                    
0000013

-c-a とで違うのは制御文字の表示方法。パイプで繋げて grep する時のやり方もちょっと変わる感じ。

# -c オプションに繋げる時
$ od -a 'UTF-8 - CRLF - EN.txt' | grep 'cr\s\snl'

# -a オプションに繋げる時
$ od -a 'UTF-8 - CRLF - EN.txt' | grep 'cr\s\snl'

同様に、cat -ecat -A でも改行コードを表示できる。

目視確認になるので、少々使いづらいか。

Windows での調べ方

続いて Windows。といっても GitBash を入れていて、基本的な Linux コマンドは使える前提で。

file コマンド

Windows GitBash にも file コマンドが入っているので、Mac と同様に使える。

$ file ./*
./EUC-JP - CRLF - EN.txt:    ASCII text, with CRLF line terminators
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./EUC-JP - LF - EN.txt:      ASCII text
./EUC-JP - LF - JP.txt:      ISO-8859 text
./Shift-JIS - CRLF - EN.txt: ASCII text, with CRLF line terminators
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./Shift-JIS - LF - EN.txt:   ASCII text
./Shift-JIS - LF - JP.txt:   Non-ISO extended-ASCII text
./UTF-8 - CRLF - EN.txt:     ASCII text, with CRLF line terminators
./UTF-8 - CRLF - JP.txt:     UTF-8 Unicode text, with CRLF line terminators
./UTF-8 - LF - EN.txt:       ASCII text
./UTF-8 - LF - JP.txt:       UTF-8 Unicode text
./UTF-8 BOM - CRLF - EN.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - CRLF - JP.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - LF - EN.txt:   UTF-8 Unicode (with BOM) text
./UTF-8 BOM - LF - JP.txt:   UTF-8 Unicode (with BOM) text

nkf

前回の記事で紹介した Windows 版 nkf を使う方法。Windows 版は --guess でも -g でも同じで、どちらでも文字コード・改行コードを両方判定してくれる。

--guess (-g) オプションを使ってみた結果は以下のとおり。

# ある日の検証結果
$ nkf -g ./*
./EUC-JP - CRLF - EN.txt:ASCII (CR)
./EUC-JP - CRLF - JP.txt:EUC-JP (CR)
./EUC-JP - LF - EN.txt:ASCII (CR)
./EUC-JP - LF - JP.txt:EUC-JP (CR)
./Shift-JIS - CRLF - EN.txt:ASCII (CR)
./Shift-JIS - CRLF - JP.txt:Shift_JIS (CR)
./Shift-JIS - LF - EN.txt:ASCII (CR)
./Shift-JIS - LF - JP.txt:Shift_JIS (CR)
./UTF-8 - CRLF - EN.txt:ASCII (CR)
./UTF-8 - CRLF - JP.txt:UTF-8 (CR)
./UTF-8 - LF - EN.txt:ASCII (CR)
./UTF-8 - LF - JP.txt:UTF-8 (CR)
./UTF-8 BOM - CRLF - EN.txt:UTF-8 (CR)
./UTF-8 BOM - CRLF - JP.txt:UTF-8 (CR)
./UTF-8 BOM - LF - EN.txt:UTF-8 (CR)
./UTF-8 BOM - LF - JP.txt:UTF-8 (CR)

# 別の日の検証結果
$ nkf -g ./*
./EUC-JP - CRLF - EN.txt:ASCII (LF)
./EUC-JP - CRLF - JP.txt:EUC-JP (LF)
./EUC-JP - LF - EN.txt:ASCII (LF)
./EUC-JP - LF - JP.txt:EUC-JP (LF)
./Shift-JIS - CRLF - EN.txt:ASCII (LF)
./Shift-JIS - CRLF - JP.txt:Shift_JIS (LF)
./Shift-JIS - LF - EN.txt:ASCII (LF)
./Shift-JIS - LF - JP.txt:Shift_JIS (LF)
./UTF-8 - CRLF - EN.txt:ASCII (LF)
./UTF-8 - CRLF - JP.txt:UTF-8 (LF)
./UTF-8 - LF - EN.txt:ASCII (LF)
./UTF-8 - LF - JP.txt:UTF-8 (LF)
./UTF-8 BOM - CRLF - EN.txt:UTF-8 (LF)
./UTF-8 BOM - CRLF - JP.txt:UTF-8 (LF)
./UTF-8 BOM - LF - EN.txt:UTF-8 (LF)
./UTF-8 BOM - LF - JP.txt:UTF-8 (LF)
  • 文字コード : Mac と同様
    • Shift-JIS・EUC-JP の判定は出来ている。
    • UTF-8 は BOM の有無が分からない。
  • 改行コード
    • ファイル単体で調べると比較的正しく判定できるのだが、複数ファイルを一括で判定しようとすると全て CR もしくは LF 扱いで出力されてしまった。

どうも改行コードの判定が Mac 版と比べるとイマイチ。また、UTF-8 の BOM も分からない。バージョンの違いだろうか。

od コマンド

Windows GitBash でも od コマンドが使える。Mac 版の od コマンドと全く同じだったので結果は省略。

grep -lzUP コマンド

これは改行コードだけを調べる方法。CR を含むファイル名を列挙する。

$ grep -lzUP '\r' ./*
./EUC-JP - CRLF - EN.txt
./EUC-JP - CRLF - JP.txt
./Shift-JIS - CRLF - EN.txt
./Shift-JIS - CRLF - JP.txt
./UTF-8 - CRLF - EN.txt
./UTF-8 - CRLF - JP.txt
./UTF-8 BOM - CRLF - EN.txt
./UTF-8 BOM - CRLF - JP.txt

オプションの内容は以下のとおり。

  • -l : マッチしたファイル名のみを表示する
  • -z : 改行の代わりに NULL 文字で区切ったものとして扱う
  • -U : grep のデフォルトの挙動が CR を取り除く挙動なので、このオプションでバイナリとして認識させ、CR を除去しないようにする
  • -P : Perl 互換の正規表現 (PCRE) として扱う。Grep のバージョン等によっては使えない。

どうも Mac では同じオプションを使えなかったので、Windows 側で紹介。多分 GNU Grep かどうかの違いなのかと。

文字コード・改行コードの調べ方まとめ

Mac の場合も、Windows GitBash の場合も、全体的には file コマンドの結果を grep して使うのが手軽で良さそうだ。nkf は導入 OS やバージョンによって細かな挙動が微妙だった。よくよく調べて使う必要がありそうだ。

# 以下で「CR」を含むファイルと BOM 付き UTF-8 のファイルを調べる
$ file ./* | grep -e 'with CR' -e 'with BOM'

# 以下で UTF-8 か ASCII でないファイルを調べる (「Non-ISO extended-ASCII text」はヒットさせる)
$ file ./* | grep -v 'UTF-8 Unicode' | grep -v ' ASCII'

用意していた検証用ファイルでの結果は以下のとおり。

$ file ./* | grep -e 'with CR' -e 'with BOM'
./EUC-JP - CRLF - EN.txt:    ASCII text, with CRLF line terminators
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./Shift-JIS - CRLF - EN.txt: ASCII text, with CRLF line terminators
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./UTF-8 - CRLF - EN.txt:     ASCII text, with CRLF line terminators
./UTF-8 - CRLF - JP.txt:     UTF-8 Unicode text, with CRLF line terminators
./UTF-8 BOM - CRLF - EN.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - CRLF - JP.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - LF - EN.txt:   UTF-8 Unicode (with BOM) text
./UTF-8 BOM - LF - JP.txt:   UTF-8 Unicode (with BOM) text

$ file ./* | grep -v 'UTF-8 Unicode' | grep -v ' ASCII'
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./EUC-JP - LF - JP.txt:      ISO-8859 text
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./Shift-JIS - LF - JP.txt:   Non-ISO extended-ASCII text

結果的に nkf は調査コマンドに含めなかったけど、変換処理は任せられるので、nkf は入れておいて損はないかと。

文字コード「超」研究 改訂第2版

文字コード「超」研究 改訂第2版