Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
指定ディレクトリ配下の Markdown ファイルに含まれる NFD・NFC 文字を一括変換する : 要「replace」「unorm」パッケージ
function(match) {
/*!
* ヒットした NFC 文字 (変数 match) を NFD 文字に変換して返却する
*
* replace パッケージの内部処理で、このファイルの中身全体を eval で変数に詰め込んで使うので、この function 外にコードを記述してはならない
*/
// NFD 文字を生成するためのパッケージ
const unorm = require('unorm');
// NFC 文字列
const nfcStrs = 'がぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポヴ';
// 置換結果文字列
let result = '';
// マッチした文字列を、Markdown リンクを構成する ")" か "]" の文字で分割し、個別に処理する
// (1行に複数のリンクがあった場合にリンク外の文字を置換しないようにするため)
const split = match.split(/\)|\]/g);
split.forEach((str, index) => {
// "(" で始まる要素がリンクパスを保持している文字列 = 置換対象となる
if(str.startsWith('(')) {
// split() でちぎった文字列 "]" 自体は失われるので入れておく
// ただし直前に閉じカッコ ")" がある場合は付与しない (Markdown の仕様上リンク文字列に閉じカッコは含まれず、リンク文字列ではないカッコ書きを認識している)
if(!result.endsWith(')')) {
result += ']';
}
if(!( new RegExp('[' + nfcStrs + ']', 'g').test(str) )) {
// 検出されたリンクの中に置換対象となる NFC 文字列がない場合は結合のみ
// (1行に複数のリンクが書かれていた場合に、リンク外の文字から置換対象を検知してしまった場合)
result += str;
}
else {
// リンク文字列部分のみ置換する
nfcStrs.split('').forEach((nfcStr) => {
// NFD 文字列を生成する
const nfdStr = nfcStr.normalize('NFD');
// NFD 文字列を NFC 文字列に変換する
str = str.replace(new RegExp(nfcStr, 'g'), nfdStr);
});
result += str;
}
// split() でちぎった文字列 ")" 自体は失われるので入れておく
result += ')';
}
else {
// 置換対象でなければ結合するだけ (split() の対象文字が含まれていた要素は空文字になるので、空文字も結合される)
result += str;
}
});
// 置換後の文字列の末尾が閉じカッコで終わっていない場合は閉じカッコを付与する
if(!result.endsWith(')')) {
result += ')';
}
// 置換後の文字列を返却する
return result;
}
/*!
* Markdown リンクや画像貼付部分の文字列から NFC 文字を検索し NFD 文字に変換するスクリプト
*/
// ファイル置換用に使用するパッケージ
const replace = require('replace');
// 検索対象文字 (NFC)
const strs = 'がぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポヴ';
replace({
// Markdown リンクや画像貼付で登場する「](」「)」の間に検索対象文字が含まれている箇所を検索する
// このやり方だと1行に複数回リンク文字列が登場した時にひとまとめに検出してしまうので、funcFile 内で分割して変換している
regex: new RegExp( '('
+ '\\]\\(' // "]("
+ '(?!(#|http))' // "#" (ページ内リンク) か "http" (外部リンク) 始まりを除外する
+ '.*?' // 任意文字列 (閉じカッコ ")" までの最短マッチ用「?」)
+ ')'
+ '([' + strs + '])' // 検索対象文字列のいずれかを含む
+ '('
+ '.*?' // 任意文字列 (閉じカッコ ")" までの最短マッチ用「?」)
+ '\\)' // ")"
+ ')',
'g'
),
replacement: false, // 置換文字列を指定しない (funcFile 使用時は false 指定が要る)
funcFile: 'nfc-to-nfd-func.js', // 文字列を置換する関数を記述したファイルの指定
paths: ['./texts'], // 検索対象ファイルの指定
include: '*.md', // 検索対象ファイルに含める拡張子
recursive: true // サブディレクトリも検索する
});
/*!
* Markdown リンクや画像貼付部分の文字列から NFD 文字を検索し NFC 文字に変換するスクリプト
*/
// ファイル置換用に使用するパッケージ
const replace = require('replace');
// NFD 文字を生成するためのパッケージ
const unorm = require('unorm');
// unorm パッケージの変換結果から NFD 形式の文字列で使用される濁点と半濁点を取得し、コレを検索する
const strs = 'ビ'.normalize('NFD')[1] + 'ピ'.normalize('NFD')[1];
replace({
// Markdown リンクや画像貼付で登場する「](」「)」の間に検索対象文字が含まれている箇所を検索する
regex: new RegExp( '('
+ '\\]\\(' // "]("
+ '(?!(#|http))' // "#" (ページ内リンク) か "http" (外部リンク) 始まりを除外する
+ '.*?' // 任意文字列 (閉じカッコ ")" までの最短マッチ用「?」)
+ ')'
+ '([' + strs + '])' // 検索対象文字列 (NFD の濁点 or 半濁点) のいずれかを含む
+ '('
+ '.*?' // 任意文字列 (閉じカッコ ")" までの最短マッチ用「?」)
+ '\\)' // ")"
+ ')',
'g'
),
replacement: false, // 置換文字列を指定しない (funcFile 使用時は false 指定が要る)
funcFile: 'nfd-to-nfc-func.js', // 文字列を置換する関数を記述したファイルの指定
paths: ['./texts'], // 検索対象ファイルの指定
include: '*.md', // 検索対象ファイルに含める拡張子
recursive: true // サブディレクトリも検索する
});
function(match) {
/*!
* ヒットした NFD 文字 (変数 match) を NFC 文字に変換して返却する
*
* replace パッケージの内部処理で、このファイルの中身全体を eval で変数に詰め込んで使うので、この function 外にコードを記述してはならない
*/
// NFD 文字を生成するためのパッケージ
const unorm = require('unorm');
// NFC 文字列
const nfcStrs = 'がぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポヴ';
nfcStrs.split('').forEach((nfcStr) => {
// NFD 文字列を生成する
const nfdStr = nfcStr.normalize('NFD');
// NFD 文字列を NFC 文字列に変換する
match = match.replace(new RegExp(nfdStr, 'g'), nfcStr);
});
return match;
}
@Neos21

This comment has been minimized.

Copy link
Owner Author

@Neos21 Neos21 commented May 13, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment