Skip to content

Commit

Permalink
Merge pull request #892 from macrat/article/update-popular-articles
Browse files Browse the repository at this point in the history
人気のある記事を読みやすく更新する
  • Loading branch information
macrat committed Jan 25, 2024
2 parents 532c5f3 + 6220a34 commit 80e6aaf
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 82 deletions.
86 changes: 67 additions & 19 deletions pages/blog/2014/10/python3-convert-int-bytes.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,92 @@
---
title: python3ならintとbytesの変換が楽勝になる
title: Python3ならintとbytesの変換が楽勝になる
pubtime: 2014-10-05T00:10:00+09:00
modtime: 2024-01-25T18:50:00+09:00
tags: [Python, 言語仕様]
description: python3.2を使って、バイナリデータとintを相互に変換変換する方法です
description: Python3.2以降で、bytes型のバイナリデータとint型の整数を相互に変換する方法の紹介です
image: [/blog/2014/10/python3-convert-int-bytes.png]
faq:
- question: Pythonのbytesをint型の整数として読み込むには?
answer: Python3.2で導入された`int.from_bytes`というメソッドを使うと便利です。
- question: Pythonのintをバイナリと見做してbytesに変換するには?
answer: Python3.2で導入された`.to_bytes`というintのメソッドを使うと便利です。
- question: Pythonのbytesをint型の整数としてパースする方法は?
answer: <pre><code>int.from_bytes(b'\x80\x00', 'little')</code></pre> のようにするとパースできます。第一引数が対象のバイト列で、第二引数がエンディアンです。
- question: Pythonのint型の整数をバイナリと見なしてbytesに変換するには?
answer: <pre><code>(123).to_bytes(4, 'big')</code></pre> のようにすると変換できます。第一引数がバイト数で、第二引数がエンディアンです。
- question: Pythonでint型の整数を格納するのに必要なバイト数を知る方法は?
answer: <pre><code>(123).bit_length()</code></pre> とすると必要なビット数が分かるので、これを利用して <pre><code>((123).bit_length() + 7) // 8</code></pre> とすると計算できます。
---

バイト列を整数にする、あるいは整数をバイト列にする。
通信とか暗号とか扱ってるとしょっちゅうやらなきゃいけない事なわけですが、pythonだと意外と面倒なのよね、これが。
通信とか暗号とか扱ってると頻繁にやらないといけないわけですが、Pythonだと意外と面倒なんですよね、これが。
C言語ならキャストしちゃえば一発なんだけどねー。

・・・なんて思っていました。ついさっきまで。
せめて楽な方法が無いかと探していたら、python3のドキュメントの中に`整数を表すバイト列を返します。`なんて記述を発見。
なんてこった、標準であるのかよ。
……なんて思っていました。ついさっきまで。

せめて楽な方法が無いかと探していたら、[公式ドキュメントの「組み込み型」のページ](https://docs.python.org/ja/3/library/stdtypes.html#int.to_bytes)に「整数を表すバイト列を返します。」なんて記述を発見。
なんと標準でそんな機能が入っていたようです。

なお、このメソッドはPython3.2以降でしか使えません。レガシー環境では注意してください。

使い方は以下のような感じになります。

# bytesからintにする

使い方はこんな感じ
``` python
>>> a = 128
>>> a.to_bytes(2, 'big') # 2バイトでビッグエンディアン
>>> a.to_bytes(2, 'big') # ビッグエンディアン(1の位が最後尾の1バイトに入る)形式で、2バイトのbytesにする
b'\x00\x80'
>>> a.to_bytes(4, 'little') # 4バイトでリトルエンディアン
>>> a.to_bytes(4, 'little') # リトリエンディアン(1の位が先頭の1バイトに入る)形式で、4バイトのbytesにする
b'\x80\x00\x00\x00'
>>> a.to_bytes() # 引数を省略すると1バイトのビッグエンディアンになる
b'\x80'
```
うわぁすごい簡単だどうしよう。
うわぁすごい簡単だ。

ちなみに、指定したバイト数(省略した場合は1バイト)で表せない大きさの場合は[OverflowError](https://docs.python.org/ja/3/library/exceptions.html#OverflowError)が送出されます。

バイト数が分からないときは、必要なビット数を教えてくれる`bit_length`メソッドを使って以下のようにすると良さそうです。

int -&gt; bytesが出来るのだからもちろんbytes -&gt; intも出来て、
``` python
>>> a = 700

>>> bit_len = a.bit_length() # 600を表すのに必要なビット数を計算する
>>> bit_len
10

>>> byte_len = (bit_len + 7) // 8 # 10ビットを入れるのに何バイト必要か計算する
>>> byte_len
2

>>> a.to_bytes(byte_len) # これで変換に使える!
b'\x02\xbc'
```

# intからbytesにする

int -&gt; bytesが出来るのだからもちろんbytes -&gt; intも出来ます。
``` python
>>> int.from_bytes(b'\x00\x80', 'big')
128
>>> int.from_bytes(b'\x80\x00\x00\x00', 'little')
128
```
こんな感じ。

**python3.2以降でしか使えない**らしいので要注意です。
いやしかし便利だなこれ、素敵だ。
こっちの場合は引数を省略するとビッグエンディアンで、長さは自動になります。

---

**Q&A**:
- Pythonのbytesをint型の整数としてパースする方法は?
`int.from_bytes(b'\x80\x00', 'little')` のようにするとパースできます。第一引数が対象のバイト列で、第二引数がエンディアンです。

- Pythonのint型の整数をバイナリと見なしてbytesに変換するには?
`(123).to_bytes(4, 'big')` のようにすると変換できます。第一引数がバイト数で、第二引数がエンディアンです。

- Pythonでint型の整数を格納するのに必要なバイト数を知る方法は?
`(123).bit_length()` とすると必要なビット数が分かるので、これを利用して `((123).bit_length() + 7) // 8` とすると計算できます。

<ins>

# 2024-01-25 追記

2024年現在もアクセス数が多いので、最新の環境で動作確認をした上で内容を充実させました。

参考: [4. 組み込み型 &mdash; Python 3.3.5 ドキュメント](http://docs.python.jp/3.3/library/stdtypes.html#int.to_bytes)
</ins>
77 changes: 56 additions & 21 deletions pages/blog/2015/11/java-character-count.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Javaで文字の出現回数を数えたい
pubtime: 2015-11-08T22:28:00+09:00
modtime: 2024-01-25T18:50:00+09:00
tags: [Java, 言語仕様, ベンチマーク]
description: Javaを使って文字列の中に特定の文字がいくつ含まれるかを数える方法です。4種類の方法をベンチマークして比較しました。
image: [/blog/2015/11/java-character-count.png]
Expand All @@ -12,70 +13,104 @@ faq:
[RuuMusic](https://play.google.com/store/apps/details?id=jp.blanktar.ruumusic)をアンドロイダーに[載せて](https://androider.jp/official/app/0e09673c7fb26c06/)いただきまして、急激にインストール数が増えてうはうはです。アンドロイダーさまさまです。
でまあ、改良を続けているわけなんですが。

ファイルパスの深さを知るためにスラッシュの数を数える、という処理があります。
このアプリの中で、ファイルパスの深さを知るためにスラッシュの数を数える、という処理があります。
ググったらなんか出て来た適当な書き方をしているのですが、どうやらこれがとても重いらしく。
しかたがないので、思い付いた4通りの書き方を試してみました。


# 方法1: for文で数える

一つめ。何も考えずに数える方法。

**ネタバレ:** この方法が最速です)

``` java
int simple(String str, char target){
int simple(String str, char target) {
int count = 0;

for(char x: str.toCharArray()){
if(x == target){
for (char x: str.toCharArray()) {
if (x == target) {
count++;
}
}

return count;
}
```
考えてません。とてもシンプルです。

何も考えていません。とてもシンプルです。


# 方法2: replace関数を使って数える

二つめ。replaceで数えたい文字を抜いた文字列を作って、長さを比較することで数える方法。

``` java
int replace(String str, char target){
int replace(String str, char target) {
return str.length() - str.replace(target + "", "").length();
}
```
短かくて良いやってことで適当に採用したのですが、あまり効率的ではないようです。

短かくて良いやってことで適当に採用していたのですが、あまり効率的ではないようです。
文字列のコピーが走るので当然といえば当然ですね。


# 方法3: split関数を使って数える

三つめ。数えたい文字で文字列を分割して、出来た配列の要素数で数える方法。

``` java
int split(String str, char target){
int split(String str, char target) {
return str.split(target + "").length - 1;
}
```
より短かくてちょっとおしゃれっぽいです。
splitメソッドは正規表現を引数に取るので、ドットのような正規表現で意味を持つ文字を探すときには要注意です。

更に短かくてちょっとおしゃれっぽいです。

ちなみにsplitメソッドは正規表現を引数に取るので、ドットのような正規表現で意味を持つ文字を探すときには要注意です。


# 方法4: 正規表現に一致した数を数える

四つめ。正規表現を使ってみた方法。

``` java
int regex(String str, char target){
int regex(String str, char target) {
Pattern p = Pattern.compile(target + "");
Matcher m = p.matcher(str);
int count = 0;

while(m.find()){
while (m.find()) {
count++;
}

return count;
}
```

長くて格好悪い上に、とても非効率っぽいです。だめだめです。

で、この四つのメソッドに3885文字の文字列を渡して100万回ずつ数えてみました。結果は以下のような感じ。

| |265文字ヒット|101文字ヒット|0文字ヒット|
|:------|------------:|------------:|----------:|
|simple | 988ms| 884ms| 884ms|
|replace| 26,009ms| 18,685ms| 10,150ms|
|split | 5,983ms| 3,179ms| 898ms|
|regex | 13,418ms| 10,237ms| 8,105ms|
# ベンチマークの結果

で、この4つのメソッドに3,885文字の文字列を渡して、100万回ずつ数えてみました。結果は以下のように。

| 方法 | 265文字ヒット | 101文字ヒット | 0文字ヒット |
|:------------------------------------------------|--------------:|--------------:|------------:|
| [for文](#方法1%3A+for文で数える) | 988ms | 884ms | 884ms |
| [replace](#方法2%3A+replace関数を使って数える) | 26,009ms | 18,685ms | 10,150ms |
| [split](#方法3%3A+split関数を使って数える) | 5,983ms | 3,179ms | 898ms |
| [regex](#方法4%3A+正規表現に一致した数を数える) | 13,418ms | 10,237ms | 8,105ms |

なんと、もの凄い差です。
何も考えずにfor文を回すのがベストなようです。
splitを使ったものだとヒットする文字が無いときに速くなるのに、regexではそうでもないというのがちょっと意外でした。splitはコンパイル結果をキャッシュしているのかもですね?

ともかくそんなわけで、難しいことを考えるのはやめましょうという結論でした。
そんなわけで、難しいことを考えるのはやめましょうという結論でした。

<ins>

# 2024-01-25 追記

読みやすさのために記事を若干再構成しました。

</ins>
105 changes: 64 additions & 41 deletions pages/blog/2020/11/css-automate-foreground-text-color.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,27 @@
---
title: CSSのfilterを使って、背景色に合わせた文字色を自動的に設定する
pubtime: 2020-11-01T01:29:00+09:00
modtime: 2024-01-25T18:50:00+09:00
tags: [Web, HTML, CSS]
description: 背景色が動的に変わる状況で、文字色が見えなくならないように良い感じに設定したい時があります。JavaScriptで書いても良いのですが面倒なので、CSSのfilterを使って上手いことやってもらう方法をご紹介します。
description: 背景色が動的に変わる状況で、文字色が見えなくならないように良い感じに設定したい時があります。JavaScriptで書くのは面倒なので、CSSのfilterを使って上手いことやってもらう方法をご紹介します。
image:
- /blog/2020/11/css-automate-foreground-text-color.png
- /blog/2020/11/css-automate-foreground-text-color-4x3.png
- /blog/2020/11/css-automate-foreground-text-color-1x1.png
faq:
- question: CSSの機能だけで背景色に合わせた文字色を選ばせるには?
answer: filterを使って、反転した色を白黒にして使ってあげればそれらしくなります
- question: CSSで色を反転させるには
answer: "`invert(100%)`というフィルタが使えます。"
- question: CSSで色を白黒にするには
answer: "`grayscale(100%)`というフィルタでグレースケールにしたあと、`contrast(100)`でコントラストを上げれば白黒になります。"
answer: filterを使って、 invert(100%) で反転した色を grayscale(100%) contrast(100) で白黒にして使ってあげればそれらしくなります
- question: CSSだけで文字や画像の色を反転させるには
answer: invert(100%) というフィルタが使えます。
- question: CSSで文字や画像を白黒にするには
answer: grayscale(100%) というフィルタでグレースケールにしたあと、 contrast(100) でコントラストを上げれば白黒になります。
---

背景色が動的に変わる状況で、文字色を良い感じに設定したい事があります。
ユーザーの入力によって色が決まるとか、外部のAPIが色を決めてるとか。

このサイトの[worksページ](/works)の各リポジトリについている、「Python」とか「TypeScript」とかの言語タグの色がそんな感じになっています。
この色はGitHubのAPIが決めているものなのですが、文字色の方は提供してくれないのでCSSで動的に計算するようにしています。

ここで使っているテクニックが地味に面白いのでご紹介します。


# やり方

色設定のコードは以下のような感じ。

``` html
<div>
<span>hello world!</span>
</div>

<style>
div {
background-color: red;
}
span {
color: red;
filter: invert(100%) grayscale(100%) contrast(100);
}
</style>
```

以上、これだけ。
背景色と同じ色を文字色にも設定しちゃって、CSSのfilterを使って見える色に変化させています。

実際色んな色でやってみると以下のような表示になります。
そこで、文字色が動的に設定される方法を考えてみました。それも、CSSだけで。
実際に動かしてみると以下のような表示になります。

<div role="img" aria-label="カラフルな27色の枠と、その上に白か黒の文字でカラーコードが表示されている。明るい色の場合は黒い文字、暗い色の場合は白い文字。">
<div style="background-color: #000000; display: inline-block; text-align: center; padding: 1em; width: 6em"><span style="color: #000000; filter: invert(100%) grayscale(100%) contrast(100)">#000000</span></div>
Expand Down Expand Up @@ -80,25 +53,51 @@ span {
<div style="background-color: #FFFFFF; display: inline-block; text-align: center; padding: 1em; width: 6em"><span style="color: #FFFFFF; filter: invert(100%) grayscale(100%) contrast(100)">#FFFFFF</span></div>
</div>

基本全部に上手いこと色を当ててくれている感じ。
いかがでしょうか。
グレー(`#808080`)に近い色はやや見づらくなってしまっていますが、それ以外はかなり上手く表示できているのではないかと思います。


ただ、中間付近の色(`#8080FF`とか)だとちょっと微妙ですね。
あとは`invert()`が効かない完全な中間色である`#808080`などはかなり見辛くなります。
# やり方

とはいえ、この簡単さで基本上手くいっているので十分でしょう。
上記のサンプルは以下のようなCSSで実現しています。

``` html
<div>
<span>hello world!</span>
</div>

<style>
div {
background-color: red;
}
span {
color: red;
filter: invert(100%) grayscale(100%) contrast(100);
}
</style>
```

以上、これだけです。

[詳しい解説は後述](#仕組み)しますが、`color``background-color`に同じ色を設定してから、文字色だけCSSのfilterで見える色に変化させる仕組みです。

なお、divとspanをセットにすると背景色にもフィルターが適用されてしまうので注意してください。


# ブラウザの対応状況

基本的なブラウザで使用することが出来ますが、IEだけは対応しないのでご注意
今回使用したCSS Filterは基本的なブラウザで使用することが出来ます

ただ、IEだけは対応しないのでご注意ください。
まあもうIEは良いでしょう。良いということにしましょう。

[![Can I useで調べたCSS Filter Effectsの対応状況。主要ブラウザだとIE11だけが非対応。](/blog/2020/11/caniuse-css-filter-effects.jpg "600x356")](https://caniuse.com/css-filters)


# 仕組み

ここからは、詳細な仕組みをご説明します。

## まずは同じ色で描画する

最初はfilterを掛ける前の状態から。
Expand Down Expand Up @@ -155,3 +154,27 @@ span {
</div>

これで完成。結構シンプルです。

---

**Q&A**:
- CSSの機能だけで背景色に合わせた文字色を選ばせるには?
→ filterを使って、`invert(100%)`で反転した色を`grayscale(100%) contrast(100)`で白黒にして使ってあげればそれらしくなります。

- CSSだけで文字や画像の色を反転させるには?
`invert(100%)`というフィルタが使えます。

- CSSで文字や画像を白黒にするには?
`grayscale(100%)`というフィルタでグレースケールにしたあと、`contrast(100)`でコントラストを上げれば白黒になります。

---

参考: [filter - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/filter)

<ins>

# 2024-01-25 追記

読みやすさのために一部構成を変更しました。

</ins>
Loading

0 comments on commit 80e6aaf

Please sign in to comment.