R, Python, DB 備忘録

データベースとか、jupyter(Python)、Rとか色々

特定の文字を入力するとIRkernelがフリーズする

現象

  • 日本語Windows、つまり文字コードShift-JIS(CP932)環境下のjupyter+Rで特定の文字を表示しようとするとフリーズする。
    • Windows(Shift-JIS)+jupyter+R というのがミソ。Pythonなら発生しないし、IRkernel+Linuxでも発生しない。
    • 具体的にはSJIS**5Cとなる2バイト文字で、「ソ」「十」「構」「申」「貼」「能」「予」「暴」など使用頻度が高いものも多い。
    • 5CはASCIIで「\(¥・バックスラッシュ)」にあたるため、エスケープ絡みでうまく動いていないと思われ。
  • なお、表示するとフリーズするが、表示さえしなければ問題ない。

解決方法

  • Rの場合、フリーズするとそこまでの分析が全ておじゃんになるのでフリーズしないようjsonのdecoder.pyを改造
    • 特定の文字が表示されそうになった場合には設定したエラーメッセージが出るようになる。
class JSONDecoder(object):
~~~
    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.

        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.

        """
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
            raise JSONDecodeError("Expecting value", s, err.value) from None
"""次のexcept:を追加"""
        except:
            obj = {"data": {"text/html": ["Characters that can not be displayed are included."],
                            "text/latex": ["Characters that can not be displayed are included."],
                            "text/markdown": ["Characters that can not be displayed are included."],
                            "text/plain": ["Characters that can not be displayed are included."]},"metadata": {},"output_type": "display_data"}
            end = len(s)
        return obj, end
  • とはいえこれだけだと、しょっちゅうエラーメッセージが出て不便
    • headもろくに使えない。
  • 特定文字を「■」に置き換えるmhead(modified Head)関数作った。
myDisplayModify <- function(str){
    if_else (stringr::str_detect(str, '[―ソ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭偆砡―]'),
             stringr::str_replace_all(str, '[―ソ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭偆砡―]', '■'),
             str
            )
}

mhead <- function(x, n = 6){
    caseFactor <- function(var) {
        myDisplayModify(as.character(var))
    }
    if (is.data.frame(x)) {
        temp.df <- x %>%
        head(n) %>%
        dplyr::mutate_if(.predicate = is.character, list(myDisplayModify) ) %>%
        dplyr::mutate_if(.predicate = is.factor, list(caseFactor))
        
        colnames(temp.df) <- myDisplayModify(colnames(temp.df))
        return(temp.df)
    } else if (is.character(x)) {
        purrr::map_chr(head(x, n), ~ myDisplayModify(.))
    } else if (is.factor(x)) {
        purrr::map_chr(head(x, n), ~ caseFactor(.))
    } else if (is.matrix(x)) {
        temp.mx <- x %>%
        head(n)
        
        colnames(temp.mx) <- myDisplayModify(colnames(temp.mx))
        rownames(temp.mx) <- myDisplayModify(rownames(temp.mx))
        return(temp.mx)
    } else {head(x, n)}
}
  • ついでにベクトルを行列に変換して表示するmxhead(modified matrix Head)も作った。
mxhead <- function(x, n = 60, ncol = 10, byrow = TRUE) {
    mhead(x, n) %>% matrix(ncol = ncol, byrow = byrow)
}

参考

  • Shift-JISコード表

charset.7jp.net