*求む!天才プログラマ*


PHP でのテキスト処理についての質問です。

現在、ブックマークレットで選択したテキスト $_s を、引用符号付きに整形するという処理を下記のように行っています。

$length = mb_strlen($_s, "UTF-8");
for($i=0; $i < $length; $i+=35){
$s .= "> ".mb_substr($_s, $i, 35 , "UTF-8")."\r\n";
}

しかし、これで

amazonはさっさと購入者だけレビューできるようにしてくれ
今だと元々公正さも何もあったものじゃないし

という2行を引用すると、

> amazonはさっさと購入者だけレビューできるようにしてくれ
今だと
>元々公正さも何もあったものじゃないし

という引用になってしまいます。

どうしたらいかなる選択範囲も<人間が見て>綺麗に見えるように処理できるでしょうか。

項目としては
・なんとなく短い文は絶対折り返さない
・しかし一定文字数で折り返す
・文頭には必ず引用符号をつける
・人間が見て綺麗に見えること
という感じです。

かなり矛盾する条件も入っているのですが、これに近づける処理を実装するためにどういった処理がいいか、ヒントだけでももらえればと思います。

回答の条件
  • 1人3回まで
  • 登録:2009/02/27 12:14:01
  • 終了:2009/03/06 12:15:05

回答(3件)

id:karaki No.1

karaki回答回数17ベストアンサー獲得回数62009/02/27 12:41:15

ポイント27pt

| > amazonはさっさと購入者だけレビューできるようにしてくれ

| 今だと

| >元々公正さも何もあったものじゃないし

と表示されるのは、ウェブページ上でそうなるのでしょうか?それとも「してくれ」の後に改行が入っているのでしょうか?


前者の場合は、ウェブページの表示の問題なのでcssで「white-space:nowrap」を指定するなどして回避する必要があります。


また、既に入力されている改行を考慮するのであれば、最初に$_sを"\r\n"でsplitして配列の各データごとに上記の処理を行い改行でつなげるなどの処理が必要だと思います。

var s = "";
var l = $_s.split("\r\n");
for (var j=0;j<l.length;j++) {
  $length = mb_strlen(l[j], "UTF-8");
  for($i=0; $i < $length; $i+=35){
    $s .= "> ".mb_substr(l[j], $i, 35 , "UTF-8")."\r\n";
  }
  $s .= "\r\n";
}

(PHPは不慣れなため、上記スクリプトは間違っているかもしれませんが、方針程度に)

id:ryuzi_kambe

回答ありがとうございます。

今回は、http://clipmail.jp/ というサービスのブックマークレットの話です。メールで送信するために完全なプレーンテキストとしてシリアライズする必要があるため、CSS による見栄え調整は意味がないかもしれません。

引用テキストは

http://koerarenaikabe.livedoor.biz/archives/51342595.html

の >61 になります。ソース上で
と改行が入っているのがわかるかと思います。


ちなみに、いただいたコードを下記のように書き直したところ、なんだかうまくいっているような感じです!

$s = "";

$l = split("\r\n",$_s);

foreach($l as $ll){

$length = mb_strlen($ll, "UTF-8");

for($i=0; $i < $length; $i+=35){

$s .= "> ".mb_substr($ll, $i, 35 , "UTF-8")."\r\n";

}

}

これで少し様子を見てみます!

2009/02/27 12:54:00
id:tail_furry No.2

敷守ほむら回答回数74ベストアンサー獲得回数72009/02/27 17:31:00

ポイント27pt

こんなかな?

define('LENGTH_CUT', 35); // 文字列を切る長さ

$_s = 'amazonはさっさと購入者だけレビューできるようにしてくれ'.PHP_EOL.'今だと元々公正さも何もあったものじゃないし';
$s = '';

$arr = split(PHP_EOL, $_s);

for ($i = 0; $i < count($arr); $i++) {
	$cnt = 0;
	for ($j = 0; $j < mb_strlen($arr[$i], "UTF-8"); $j++) {
		if ($cnt == 0) $s .= "> ";
		$s .= mb_substr($arr[$i], $j, 1, "UTF-8");
		$cnt += strlen(mb_substr($arr[$i], $j, 1, "UTF-8")) == 1 ? 1 : 2;
		if ($cnt > LENGTH_CUT) {
			$cnt = 0;
			$s .= PHP_EOL;
		}
	}
	$s .= PHP_EOL;
}

echo nl2br($s);

表示する時にフォントは等角フォントで。

id:zista No.3

zista回答回数1ベストアンサー獲得回数02009/02/27 18:53:04

ポイント26pt

正規表現で。

$s = preg_replace("/([^\r\n]{0,35})(\r\n)?/u","> $1 \r\n",$_s);

最後に一行余分に入ってしまうのが難点。正攻法があれば教えて欲しいです。

とりあえず以下のように少し修正してみました。

$s = preg_replace("/([^\r\n]{1,35})(\r\n)?|\r\n/u","> $1 \r\n",$_s);

  • id:ryuzi_kambe
    ちなみに文中サンプルは文末の改行を取り除いていないために問題が起こっているのですが、そこを取り除いてしまうとニュアンスが変わってしまうのでうまくありません。

    ※つまり、

    > amazonはさっさと購入者だけレビューできるようにしてくれ今だと元々
    > 公正さも何もあったものじゃないし

    となってしまうのはNGということです。

    今回の場合は

    > amazonはさっさと購入者だけレビューできるようにしてくれ
    > 今だと元々公正さも何もあったものじゃないし

    とするのが理想なのですが、そうするともう少し違う長さの引用でレイアウト崩れが起きてしまいそうです。

    どういったテストパターンを用意すればいいかというブレスト結果だけでも、十分回答として意味がありますのでぜひぜひよろしくお願いいたします。
  • id:ryuzi_kambe
    また、wordwrap という関数もあるようなのですが、文字コード指定が出来ないのでマルチバイトでは使い物にならないらしいです。
    http://phpspot.net/php/man/php/function.wordwrap.html

    そのため今回も手動で処理を書いています。
  • id:ryuzi_kambe
    ちょっとおおげさになりますが、形態素解析を使って文意を崩さない整形をするものひとつの手かと思っています。でも、ウェブ上のランダムなテキストでは、かえって難しいかもしれないですね…。
  • id:gaziro2000
    何文字くらいで改行?とかいう条件は無いのでしょうか?
    それがあるとすれば、改行を削除して、
    茶筅などで形態素解析して最大文字数の直前の要素の前に改行を入れる。
    などとすれば良いのではないでしょうか?
  • id:ryuzi_kambe
    ソースにありますように、35文字(1バイトで70文字)という感じです。

    茶筅もこんど使ってみたいと思います。

    コメントありがとうございました。
  • id:tail_furry
    開ける前にボクの回答にバグがあったので書き込みますが、
    >|
    if ($cnt > LENGTH_CUT) {
    |<
    のブロックは
    >|
    if ($cnt == 0) $s .= "> ";
    |<
    の前に移動してください。
    あと、LENGTH_CUTの定数はバイト数です。70バイトで切りたい場合は70に。
  • id:zero-uhura
    「形態素解析」が必要でしょうね、他人さまのソースですが下記のがお手軽そうで良さそうではないでしょうか。

    Javascriptだけで書かれたコンパクトな分かち書きソフトウェア(chasen.org)

    http://chasen.org/~taku/software/TinySegmenter/

    上のPHP版

    http://programming-magic.com/?id=172

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません