※改行については特に規定していません
'01234567890123456789012345'.match(/.{1,10}|^/ug); // ['0123456789', '0123456789', '012345']
解説
まず始めのところが1文字以上10文字以下の部分にマッチしてくれます。うしろの|^
の部分で空文字を渡されたときに['']を返すようにしています。
※改行については特に規定していません
'01234567890123456789012345'.match(/.{1,10}|^/ug); // ['0123456789', '0123456789', '012345']
まず始めのところが1文字以上10文字以下の部分にマッチしてくれます。うしろの|^
の部分で空文字を渡されたときに['']を返すようにしています。
HHKB HYBRID Type-Sを買ったのでレビューします。
これはまあ当然なのですが(35,000円もするので)、やはり打ちやすいですね。底につかないので指が疲れにくいです。
ぼくは研究室で1年間Realforceを使っていましたが、打鍵感はそんなに変わらない気がします。
無線接続というとラグで使い物にならない印象がありますが、HHKBはほぼラグがありません。無線と有線で差が全くないです。タブレットやスマホと接続してもほとんどラグがなかったので、ほとんどの環境でラグがないと思われます。タブレットと無線で繋いでブログを書くという芸当ができるのはすごく楽でいいですね。
HHKBといえばFnキーを使った移動ですが、これはすぐ慣れるので全く問題ありません。それよりもチルダキーの位置が右上にあるのが非常に気になります(US配列の場合チルダキーは左上が多い)。チルダキーは結構使うので、真反対の位置に置かれると脳が混乱します。
また、僕はjキーに右手人差し指を置いてタイピングをする癖があります。HHKBはキーが小さいため、この我流ホームポジションだと感覚が狂います。左手はともかく、右手のタイプミスがかなり目立っています。まあ、ホームポジションが我流なのが問題なので、きちんとホームポジションができていればおそらく問題ありません。
US配列には半角全角キー、無変換・変換キーがありません。そのため、日本語入力はCtrl + Space(あるいはCtrl + Shift + Space)で切り替える必要があります。僕は普段、無変換キーと変換キーで入力切替できるよう設定しているため、入力を切り替えるときに複数キーを押すのは面倒なんじゃないか?と思っていましたが、慣れるとそこまで手間に感じません。
Type-SでないHHKBを使ったことがないので比較ができませんが、Type-Sといいつつ結構カチャカチャと音がなっています。別に不満というわけではないですが、「これでType-Sってことは無印はどれだけ音が大きいんだ…」と思いました。もし無印を買っていたら音が気になっていたかもしれません。下手に金をケチるよりType-Sを買ったほうが良いのかもしれません。
まとめると、「慣れればかなり快適」ですね。35,000円かける価値はあると思います。
直感に反しているExclude型についてconditional typeの話をしつつ解説します。
Union型から特定の要素を取り除く型です。ある型から特定のプロパティを取り除きたいときに使えます。
interface Person { name: string; age: number; country: string; } type PersonWithoutAge = Pick<Person, Exclude<keyof Person, "age">>;
Exclude型は簡潔に実装できます。
type Exclude<T, K> = T extends K ? never : T;
わけがわからないと思うので1つずつ解説します。
extendsは「右辺は左辺のサブクラスであるか」を判定します。特にここではプロパティ名同士の比較になるので、単に等しいかどうかを判定しています。
そして、T extends Kが真であったならneverを、偽であったならばTを返します。
動作をみて分かるとおり、これは三項演算子、もっといえばif文のような役割を果たしています。そのため、名前もconditional typeとなっています。
さて、ここまで読んでいて「おや?」と混乱してきませんか?僕もとても困惑しました。なぜならExclude<keyof Person, "age">
は書き下すとkeyof Person extends "age" ? never : keyof Person
となるわけで、意味がわからないからです。ご安心ください。これであっています(この書き下しは間違えています)。このあときちんと説明します。
conditional typeはT extends KのTがUnion型の場合、以下のように分配が起きます。
T extends K ? never : T -> T = (U1 | U2 | U3)とする -> (U1 extends K ? never : U1) | (U2 extends K ? never : U2) | (U3 extends K ? never : U3)
これを見ればExclude<keyof Person, "age">
でなぜうまく行くかはほとんど明らかですね。
優先度付きキューを実装する必要に駆られたので書きました。
TypeScript
class PriorityQueue<T> { private container: T[] = []; private size = 0; private comp: (a: T, b: T) => boolean; constructor(comp = (a: T, b: T) => a < b) { this.comp = comp; } push(val: T) { let index = this.size; this.container[this.size] = val; ++this.size; for (let parent = 0|(index-1)/2; parent >= 0 && this.comp(this.container[parent], this.container[index]); index = parent, parent = 0|(index-1)/2) { const tmp = this.container[index]; this.container[index] = this.container[parent]; this.container[parent] = tmp; } } pop() { this.container[0] = this.container[this.size-1]; this.container.pop(); --this.size; for (let index = 0, l = 1, r = 2; l < this.size && (this.comp(this.container[index], this.container[l]) || this.comp(this.container[index], this.container[r])); l = index * 2 + 1, r = index * 2 + 2) { let target = l; if (this.comp(this.container[index], this.container[r])) target = r; if (this.comp(this.container[index], this.container[l]) && this.comp(this.container[index], this.container[r])) if (this.comp(this.container[r], this.container[l])) target = l; else target = r; const tmp = this.container[index]; this.container[index] = this.container[target]; this.container[target] = tmp; index = target; } } top() { return this.container[0]; } empty() { return this.size == 0; } }
JavaScript
class PriorityQueue { constructor(comp = (a, b) => a < b) { this.size = 0; this.container = []; this.comp = comp; } push(val) { let index = this.size; this.container[this.size] = val; ++this.size; for (let parent = 0|(index-1)/2; parent >= 0 && this.comp(this.container[parent], this.container[index]); index = parent, parent = 0|(index-1)/2) { const tmp = this.container[index]; this.container[index] = this.container[parent]; this.container[parent] = tmp; } } pop() { this.container[0] = this.container[this.size-1]; this.container.pop(); --this.size; for (let index = 0, l = 1, r = 2; l < this.size && (this.comp(this.container[index], this.container[l]) || this.comp(this.container[index], this.container[r])); l = index * 2 + 1, r = index * 2 + 2) { let target = l; if (this.comp(this.container[index], this.container[r])) target = r; if (this.comp(this.container[index], this.container[l]) && this.comp(this.container[index], this.container[r])) if (this.comp(this.container[r], this.container[l])) target = l; else target = r; const tmp = this.container[index]; this.container[index] = this.container[target]; this.container[target] = tmp; index = target; } } top() { return this.container[0]; } empty() { return this.size == 0; } }
new PriorityQueue()
でインスタンスを生成できます。デフォルトは降順で要素が出てきます。
const q = new PriorityQueue<number>(); for (const e of [4, 1, 6, 2, 5, 3, 9, 10, 8, 7]) { q.push(e); } while (!q.empty()) { console.log(q.top()); q.pop(); }
比較関数を渡すことで優先順を変えることができます。
const q = new PriorityQueue<number>((a:number, b:number) => a>b); // 昇順 for (const e of [4, 1, 6, 2, 5, 3, 9, 10, 8, 7]) { q.push(e); } while (!q.empty()) { console.log(q.top()); q.pop(); }
結構こういう要求はあるとおもいます。
/static
へのリンクが途切れる<Link>
で遷移するとbasepathが変わるつまり、サブディレクトリ以下でNext.jsを使ったSPAをしたい!!という人向けの記事です。
/static
へのリンクをサブディレクトリ以下になるようにするたとえばexample.com/next-app
でデプロイしたいとき、example.com/next-app/_next/static
以下にJSファイルなどは置かれます。しかし、なにも設定しないままだとNext.jsではexample.com/_next/static
へのリンクを張るため404となってしまいます。
これを解決するには、next.config.jsでassetPrefixを設定する必要があります。
const isProd = process.env.NODE_ENV == 'production'; const url = isProd ? 'https://example.com/next-app' : ''; module.exports = { assetPrefix: url, }
これでローカルでも本番環境でも/static
へアクセスできるようになります。
<Link>
で遷移するとbasepathが変わる上の方法で/static
へアクセスできるようになりました。しかし、実はルーティングをしている場合これだけでは対応が不十分です。
たとえば以下のような<Nav>
を考えます。
import * as React from 'react'; import Link from 'next/link'; const Nav = () => ( <nav> <ul> <li><Link href="/"><a>Top</a></Link></li> <li><Link href="/about"><a>About</a></Link></li> <li><Link href="/content"><a>Content</a></Link></li> </ul> </nav> );
このNav要素はローカル環境ではなんの問題もなく動作します。しかし、本番環境ではうまく動作してくれません。たとえば本番環境でAboutをクリックすると、example.com/about
へとURLが変わります。もうおわかりですね。この状態でリロードするとページが読み込まれません。
この問題の解消方法はとても簡単です。as
属性をつけてあげるだけです。
<Link href="/about" as="/next-app/about"><a>About</a></Link>
しかし、今度はローカルでうまく動作しません。困りましたね。
参考: Deploy your NextJS Application on a different base path (i.e. not root)
どうやらNext.jsにはnext.config.jsから値を取ってくる機能があるようです。
import getConfig from 'next/config'; const {publicRuntimeConfig} = getConfig();
こうするとnext.config.jsで設定したpublicRuntimeConfigの値を取ってこられるようになります。あとはこれを設定して、Linkのasでこれを使った設定をしてやれば完成です。詳しいコードはこちらを参考にしてください。