文字列を取り、スペースなしでその長さをチェックする小さな perl 関数を書きました。基本的なコードは次のようになります。
sub foo
{
use utf8;
my @wordsArray = split(/ /, $_[0]));
my $result = length(join('', @wordsArray));
return $result;
}
この関数に特殊文字 (ヘブライ文字など) を含む文字列を指定すると、うまく機能するようです。この問題は、文字セットが utf8mb4 の MySql 列からの値を使用するときに発生します。このような場合、計算される値は前の例の値より高くなります。
このような動作が発生する理由は推測できます。特殊文字はテーブルに 4 バイトで記述されているため、utf8 エンコーディングでは各文字が 2 文字として計算されます。
utf8mb4として定義されたDBテーブルからの文字列から正しい文字数を取得するために、上記を解決する方法を知っている人はいますか?
編集:
上記のコードに関するその他の情報:
関数の引数として使用される DB 列は、utf8mb4_unicode_ci の照合で VARCHAR(1000) 型です。次のように構成されたMySql接続を介して行をフェッチしています:
$mySql = DBI->connect(
"DBI:mysql:$db_info{'database'}:$db_info{'hostname'};mysql_multi_statements=1;",
"$db_info{'user'}",
"$db_info{'password'}",
{'RaiseError' => 1,'AutoCommit' => 0});
...
$mySql->do("set names utf8mb4");
データ値の例は、"שלום עולם" (ヘブライ語で "Hello World" を意味します) です。
1) 呼び出すとfoo($request->{VALUE});
(VALUE は DB からの列データ)、結果は 16 になります (各ヘブライ文字は 2 文字としてカウントされ、その間の 1 つのスペースは無視されます)。この場合のダンパーは次のとおりです。
$VAR1 = "\327\251\327\234\327\225\327\235 \327\242\327\225\327\234\327\235";
2) 呼び出す場合foo("שלום עולם");
:
を宣言する
use utf8;
と、結果は 8 になります (この文字列には 8 つの可視文字があるため)。この場合のダンパー (Useqq=1) は次のとおりです。$VAR1 = "\x{5e9}\x{5dc}\x{5d5}\x{5dd} \x{5e2}\x{5d5}\x{5dc}\x{5dd}";
「use utf8;」を宣言しない場合、結果は 16 で、DB から値を送信する場合と同様です。
$VAR1 = "\327\251\327\234\327\225\327\235 \327\242\327\225\327\234\327\235";
作業を開始する前に、受信した値を UTF8 に変換する方法を見つける必要があるようです。