tohokuaikiのチラシの裏

技術的ネタとか。

文字の幅を揃えてくれるようにカットしてくれるmb_substr

自分がやりたいのは等幅フォントで同じくらいの長さになるようにしたい。
主にレイアウトが重視される場合に。

分かりにくいので、たとえばで言うけど、元の文字列として

  • abcdefghijklmnopqrsiuvwxyzABCDEFGHIJKLMNOPQRSIUVWXYZ
  • あいうえおかきくけこさしすせそたちつてとなにぬねのは
  • aあbいcうdえeおfかgきhくiけjこkさlしmすnせoそpたqちrつsてiとuなvにwぬxねyのzは

ってあったものを15文字でそろえたい場合
mb_substrだと

  • abcdefghijklmno
  • あいうえおかきくけこさしすせそ
  • aあbいcうdえeおfかgきh

となってしまう。

もちろん15文字なんだけど、長さが違う。

もちろんsubstrだと日本語が入った場合に途中で切ってしまうので使えない。

そこで、以下の関数を作った。

<?php
function mono_substr($str, $start, $length = null)
{
    $str_euc = mb_convert_encoding($str, 'EUC-JP', 'UTF-8');
    
    $count = 0;
    $r_length = 0;
    $ret = "";
    for ($i=0; $i < mb_strlen($str_euc, 'EUC-JP'); $i++){
        $c = mb_substr($str_euc, $i, 1, 'EUC-JP');
        $l = strlen($c);
        $count += $l;
        if ($count >= $start){
            
            if (!is_null($length)){
                if ($r_length + $l > $length){
                    break;
                }
                else {
                    $ret .= $c;
                    $r_length += $l;
                }
            }
        }
    }
    
    return mb_convert_encoding($ret, 'UTF-8', 'EUC-JP');
}

これだと、さっきのを15文字で切った場合

  • abcdefghijklmno
  • あいうえおかき
  • aあbいcうdえeお

となって、おお、思った通りの美しさである。

ただし、文字コードはUTF8前提であるし文字カウントをする時にEUC-JPに変換してるのでUTF-8特有の文字は使えません。