ルモーリン
ホーム更新サービス雑談ランドナーコースガイド鉄ゲタ自転車Linuxリンク連絡先

全角半角混在文字列の切り詰め

きっかけ

このツイートを見て挑戦。

コード

2種類の方法で切り詰めました。 1つ目は文字列を画像化した際のピクセル数、2つ目はUnicodeの全角/半角の区別です。 フォントファイルを指定する都合で、今回はVPS(CentOS)での実行をサボりました。
#!/usr/bin/perl -w

use utf8;
use warnings;
use strict;
use open IO => ":utf8";

use Encode::Locale;
use GD::Image;
use Unicode::EastAsianWidth;

binmode STDOUT, ":encoding(console_out)";

$| = 1;

my @sample = qw /
	本日は晴天。
	_本日は晴天。
	本日は晴天なり。
	_本日は晴天なり。
/;

for (@sample) {
	print "    '123456789.12'\n";
	print "原文 :'$_'\n";
	my $pixel = 140;
	my $result = pixel_cut($pixel, $_);
	print "${pixel}px :'$result'\n";

	my $half = 12;
	$result = half_cut($half, $_);
	print "半角$half:'$result'\n";

	print "\n";
}

exit;



sub pixel_cut {
	my ($pixel, $s) = @_;

	my $is_crop = 0;
	my @bounds = GD::Image->stringFT(0, 'c:/WINDOWS/Fonts/msgothic.ttc', 16, 0, 20, 40, $s);
	while ($pixel < $bounds[2] - $bounds[0]) {
		substr($s, -1, 1) = '';
		@bounds = GD::Image->stringFT(0, 'c:/WINDOWS/Fonts/msgothic.ttc', 16, 0, 20, 40, $s);
		$is_crop = 1;
	}
	if ($is_crop) {
		substr($s, -1, 1) = "…";
	}

	return $s;
}



sub half_cut {
	my ($half, $s) = @_;

	my $is_crop = 0;
	my $count = half_count($s);
	while ($half < $count) {
		substr($s, -1, 1) = '';
		$count = half_count($s);
		$is_crop = 1;
	}
	if ($is_crop) {
		substr($s, -1, 1) = "…";
	}

	return $s;
}


sub half_count {
	my ($s) = @_;

	return (() = $s =~ /\p{InHalfwidth}/g) + 2 * (() = $s =~ /\p{InFullwidth}/g);
}

実行結果

こんな感じ。
    '123456789.12'
原文 :'本日は晴天。'
140px :'本日は晴天。'
半角12:'本日は晴天。'

    '123456789.12'
原文 :'_本日は晴天。'
140px :'_本日は晴…'
半角12:'_本日は晴…'

    '123456789.12'
原文 :'本日は晴天なり。'
140px :'本日は晴天…'
半角12:'本日は晴天…'

    '123456789.12'
原文 :'_本日は晴天なり。'
140px :'_本日は晴…'
半角12:'_本日は晴…'