1
0

More than 1 year has passed since last update.

マークダウン形式文字列のコードブロック外に存在する特定の記号をサニタイズする。

Last updated at Posted at 2022-02-05

下記のようなコードブロックとコードブロック外の混在するマークダウン形式の文章があるとします。

33178870c736b737203c8b0678552038.png

以下の要件で文字列をサニタイズします。

・以下の記号をエスケープシーケンスに置き換えます。
(ただしコードブロック内の記号については置き換えない。)
(ただし、画像のURL内に含まれる&は置き換えない)

& は & に置き換え
< は  &lt;  に置き換え
>  は &gt;  に置き換え
" は &quot;  に置き換え
' は &#x27;  に置き換え

実装方針

1.文字列を「```」で分割する。
2.分割されたブロックがそれぞれコードブロック部分か、そうでないかを判別する。
3.コードブロック外の文字列の場合、上記の記号を置き換える。
4.画像URLないの&については置き換えない。
5.分割した文字列を再結合する。

サニタイズ後の文字列

ここはコード外です。# 大文字&lt; &gt; &amp; &#x27; &quot;&lt;&gt;&amp;&#x27;&quot;```javascriptconst test = () => {    console.log('テスト')const one = 1;const two = 2;if(one < tow && one >=0){   console.log("over") }}```コード外です2。*斜体*&lt;a onmouseover=alert(document.cookie)&gt;click me!&lt;/a&gt;```javascriptonmouseover=alert(document.cookie)>click me!</a>```![image](https://firebasestorage.googleapis.com/v0/b/searchistory.appspot.com/o/images%2F45d84e1d-5c54-48df-ae98-8ec8c7a6cdd1?alt=media&token=4c436dd6-92f7-41a2-8211-0cd41f769278) 

1についての関数(文字列を「```」で分割する。)

const originWord = "```javascript <inCodeWord> ``` <outCodeWord>  ```javascrpt <inCodeWord> ```"

const sanitize = (originWord) => {
  const splitReg = /(?=```)/
  const splitedArray = originWord.split(splitReg);

  console.log(splitedArray);
}

//結果
//["```javascript <inCodeWord> ","``` <outCodeWord>  ","```javascrpt <inCodeWord> ","```"]

// 正規表現の/(?=```)/でsplitすることにより肯定先読みで、
// ```の直前の位置で文字列を分割し配列化する。

2についての実装追加(分割されたブロックがそれぞれコードブロック部分か、そうでないかを判別する。)

配列の各文字列の先頭の```の直後に文字(言語名)が続く場合はコードブロック内、そうでなければコードブロック外と判定する。

const originWord = "```javascript <inCodeWord> ``` <outCodeWord>  ```javascrpt <inCodeWord> ```"

const sanitize = (originWord) => {
  const splitReg = /(?=```)/
  const splitedArray = originWord.split(splitReg);

  for (let i = 0; i < splitedArray.length; i++) {
    const splitReg = /^```\w+\s/
    if (!splitReg.test(splitedArray[i])) {
      console.log("out code");
    } else {
      console.log("in code");
    }
  }
}

sanitize(originWord)

//結果
//"in code", "out code", "in code"

3についての実装追加(コードブロック外の文字列の場合、上記の記号を置き換える。)

const originWord = "```javascript <inCodeWord>' ``` <outCodeWord>  ```javascrpt <inCodeWord> ```"

//記号置き換え関数を追加
const escapeHTML = (word) => {
  return word.replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, "&#x27;");
}

const sanitize = (originWord) => {
  const splitReg = /(?=```)/
  const splitedArray = originWord.split(splitReg);

  for (let i = 0; i < splitedArray.length; i++) {
    const splitReg = /^```\w+\s/
    if (!splitReg.test(splitedArray[i])) {
      const sanitizedBlockWord = escapeHTML(splitedArray[i])
      console.log(sanitizedBlockWord)
    } else {
      console.log(splitedArray[i]);
    }
  }
}

sanitize(originWord)

//結果
//"```javascript <inCodeWord>' "
//"``` &lt;outCodeWord&gt;  "
//"```javascrpt <inCodeWord> "

4についての実装追加(画像URL内の&については置き換えない。)


//略 

const originWord = "```javascript &  ``` media&token &```"

const escapeHTML = (word) => {
  return word.replace(/(?<!(media))&(?!(token))?/g, '&amp;')//修正
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, "&#x27;");
}

//略 

//結果
//"```javascript &  "
//"``` media&token &amp;"
//"```"

//escapeHTMLの&の置き換え関数を修正
//画像URLに含まれる&は必ず media&tokenという形式なので、正規表現で置き換え対象から除外する。

5の実装追加(分割した文字列を再結合する。)

const originWord = "```javascript <inCodeWord> ``` <outCodeWord>&  media&token ```javascrpt <inCodeWord> ```"

const escapeHTML = (word) => {
  return word.replace(/(?<!(media))&(?!(token))?/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, "&#x27;");
}

const sanitize = (originWord) => {
  const splitReg = /(?=```)/
  const splitedArray = originWord.split(splitReg);

  let sanitizedAllWord = ""

  for (let i = 0; i < splitedArray.length; i++) {
    const splitReg = /^```\w+\s/
    if (!splitReg.test(splitedArray[i])) {
      sanitizedAllWord = sanitizedAllWord + escapeHTML(splitedArray[i]);
    } else {
      sanitizedAllWord = sanitizedAllWord + splitedArray[i];
    }
  }
  return sanitizedAllWord;
}

console.log(sanitize(originWord));

//結果
//"```javascript <inCodeWord> ``` &lt;outCodeWord&gt;&lt;  media&token ```javascrpt <inCodeWord> ```"

以上です。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0