スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[PHP] 一定文字数で強制的に改行を挿入したい

というオーダがあったので。
作ってみたけど非常にまわりくどいので正攻法なのかどうか。
オーダとしては、とある文字列の
「1行が半角76文字を超えたらそこで強制的に改行を入れてほしい」
というもの。聞く限りはシンプルな話です。

でも結構めんどくさい手法で実現しました。
最初はこれを実現するために近い関数あるだろう、ということで
str_split() を見つけ、これを使おうとしました。

str_split - 文字列を配列に変換する
http://phpspot.net/php/man/php/function.str-split.html

上記の場合でいうと、76文字で文字列を分割してやって、分割したそれぞれを改行を
はさんで結合してやれば改行が挿入されますよね。

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAA + "\n" + AAAAAAAAAAAAAAAAAAAAA + "\n" + AAAA

とはいえ、扱うのは日本語なので、それを考慮する必要があります。
でもマルチバイト関数に mb_str_split() が……。ないじゃん!
そんなに難しくないだろうから自作するか……と思い、でもどっかに
似たのがあるだろう、と探して流用をしてみる。


//===============================================
// str_split MB版 ( 文字列, エンコード, 分割最大長(デフォルト:1) )
//===============================================
function mb_str_split( $str, $enc, $length = 1 ) {

//空であれば偽を返す
if ( $length <= 0 ) return FALSE;

//配列の初期化
$result = array();

for ( $i = 0, $idx = 0; $i < mb_strlen( $str, $enc ); $i += $length ) {
$result[$idx++] = mb_substr( $str, $i, $length, $enc );
}
//結果を戻す
return $result;
}


で、作ってみてテストする前に気付いたのですが、先のオーダは「半角76文字」
これだと確かに文字数でカウントできるものの、どんな文字でも1文字換算されて
しまいます。
なら strlen() でバイト数を測ればいいのかというと、strlen() は文字コードで
全角文字を3バイトで判断するなどするので、あんまり私は信用しておりません。

日本語文字列のバイト数取得にstrlenだけではダメな理由 -PHP
http://www.cpa-lab.com/tech/0144

というわけで方針を変えて、
「頭から一文字ずつ拾ってバイト数(半角1全角2のみなしバイト)をカウントし、
 一定文字数を超えるようであればそこで改行を挟み込む」
ことにしました。
バイト数(半角1全角2のみなしバイト)の測定は半角→全角の変換を行い、それが
変換前と一致するか否かで判断しました。

//===============================================
// 文字列が半角か全角であるかを判別する
// (正確には半角が混在しているか)
//===============================================
function checkHankaku( $str, $enc ){
if( strlen( $str ) <= 0 ){
return( FALSE );
}
//全角変換をして異なっているかを確認する
if( $str != mb_convert_kana($str, "AKS", $enc ) ){
//異なっているので半角が混在する
return( TRUE );
}else{
//すべて全角である
return( FALSE );
}
}


1文字ずつこの関数にかければその文字が半角か全角かわかるはず。

で、通しての処理としては

//===============================================
// 一定文字数で改行を挿入する
//===============================================
function insertLfCode( $str, $n, $enc ){
//空であれば空を返す
if( strlen( $str ) <= 0 ){
return( "" );
}
//初期化
$str_join = "";
$str_char = "";
$cnt = 0;
//一文字ずつ処理
for( $i = 0; $i < mb_strlen( $str, $enc ); $i++ ){
$str_char = mb_substr( $str, $i, 1, $enc );
//セットする文字が半角か全角であるか判別しカウント
$cnt += checkHankaku( $str_char, $enc ) ? 1 : 2;
//カウント数が規定文字数以上になっていれば
if( $cnt >= $n ){
$cnt = 0;
$str_join .= "\n";
}
//一文字ずつ末尾にセット
$str_join .= $str_char;
}
return( $str_join );
}


をベースの処理(1行の文字列に一定数で改行を挿入)として、

//==========================================================
// 一定文字以上改行がなければ強制的に改行を挿入する
//==========================================================
function insLF( $str, $n, $enc ){
//------------------------
//初期化
//------------------------
$str_join = "";
$str_ret = "";

// まず改行を統一
$str = str_replace( "\r\n", "\n", $str );
$str = str_replace( "\r", "\n", $str );

// 次に改行で配列に分割
$buf_txt = explode( "\n", $str );
// それぞれ分割されたものをさらに一定文字に分割し、改行で連結することで改行を挿入
for( $i = 0; $i < count( $buf_txt ); $i++ ){
$str_line = $buf_txt[$i];
$str_line = str_replace( "\r", "", $str_line );
$str_line = str_replace( "\n", "", $str_line );
//一定文字以上で改行がなければ
if( getDummyByteSize( $str_line, $enc ) > $n ){
$str_line = insertLfCode( $str_line, $n, $enc );
}
//連結を行う
$str_join .= $str_line;
//もともと改行で分割されていたため、改行をつけなおす
$str_join .= "\n";
}
//連結で生成した文字列を戻す(いちおうトリミングを行う)
$str_ret = trim( $str_join );

return( $str_ret );
}


getDummyByteSize() についてはここではソースはあげていませんが、
前述の checkHankaku() を一文字ずつかけて、文字列についてみなしのバイト数を
算出するものを作成しました。

元の改行交じりの文字列をいったん一行ずつに分割し、件の改行挿入処理を
各行に行い、再度連結するということをやってます。

非常にめんどくさいことをやっております!
なんかもっとシンプルにできたような気もしますが……。
関連記事
スポンサーサイト

テーマ : PHP
ジャンル : コンピュータ

comment

管理者にだけメッセージを送る

検索フォーム
リンク
最新記事
最新コメント
カテゴリ
RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。