首页 > 解决方案 > 在 PHP 中拆分、计数和格式化多字节字符

问题描述

我正在构建一个实验性的 PHP 应用程序,用于处理Cyrillic UTF-8 characters 中的诗歌。我想实现以下目标:

我试过的

除了不知道该怎么做之外,我还遇到了一些小问题。这是我现在做的一步一步。

我通过post方法收集一首诗。英文诗仅用于说明目的。

文本示例:

We shall not cease from exploration 
And the end of all our exploring
Will be to arrive where we started
And know the place for the first time.

我对这些步骤进行了编号,希望使评论更容易。


1. 获取带标签和不带标签的值

这是htmlentities()通过 textarea 提交后的样子:

$string = "We shall not cease from exploration<br /> And the end of all our exploring<br /> Will be to arrive where we started<br /> And know the place for the first time."

我如何输出换行符:

$poem = nl2br($string);

这是没有标签的副本:

$droptags = strip_tags($poem);

2.计数字符

这是我对缺少计数循环的初步尝试count_chars()

$poem2array = preg_split('//u', $droptags, null, PREG_SPLIT_NO_EMPTY);
$unique_characters = array_unique($poem2array);

输出如下:

(
[0] => W
[1] => e
[2] => 
...
)

3. 将行拆分为数组

分成几行:

$lines = preg_split('<br />', $showtags);

我的问题是数组看起来像这样:

(
[0] => We shall not cease from exploration<
[1] => >
And the end of all our exploring<
[2] => >
Will be to arrive where we started<
[3] => >
And know the place for the first time.
)

我尝试将文本拆分为嵌套数组。我知道它坏了,因为我只能得到最后一行。

foreach($lines as $line) {
      $line = preg_split('//u', $line, null, PREG_SPLIT_NO_EMPTY);
    }

4. HTML 样式

至于数组的 HTML 样式,我没有想法。我的参考数组看起来像这样:

$vowels = array("a", "e", "i");
$consonants = array("b", "c", "d");

$fontcolor = array("vowels" => "blue",
                "consonants" => "orange");

标签: phphtmlarraysstringmultibyte

解决方案


如果你想计算文本中元音和辅音的出现次数,你应该计算每个字母的出现次数,然后检查它是元音还是辅音。

要将字符串拆分为字符数组,您应该使用mb_str_split(). 如果您坚持使用 PHP <= 7.3,那么您必须使用preg_split('//u', $line, null, PREG_SPLIT_NO_EMPTY);.

您可以使用array_count_values()将数组减少到字母频率的计数。然后只需分别计算元音和辅音即可。

要正确处理多字节字符串,您应该使用mbstring扩展名。例如mb_strtolower是 的多字节版本strtolower()并且mb_str_split()是 的多字节版本str_split()

<?php

$poem = <<<'POEM'
We shall not cease from exploration 
And the end of all our exploring
Will be to arrive where we started
And know the place for the first time.
POEM;

$vowels = array("a", "e", "i", "o", "u");
$consonants = array_diff(range('a', 'z'), $vowels); // not necessary to diff because of elseif. Just for demonstration

$letterFrequencyInsesitive = array_count_values(mb_str_split(mb_strtolower($poem)));
$noVowels = 0;
$noConsonants = 0;
foreach ($letterFrequencyInsesitive as $letter => $freq) {
    if (in_array($letter, $vowels, true)) {
        $noVowels += $freq;
    } elseif (in_array($letter, $consonants, true)) {
        $noConsonants += $freq;
    }
}

echo 'Number of vowels: '.$noVowels.PHP_EOL;
echo 'Number of consonants: '.$noConsonants;

如果您想分别格式化每个字母,那么可能最简单的方法是将每个字母包装在<span>标签中并应用一个类。

$formattedOutput = '';
$fontcolor = array("vowels" => "blue",
    "consonants" => "orange");

foreach (mb_str_split($poem) as $char) {
    $lowercase = mb_strtolower($char);
    if (in_array($lowercase, $vowels, true)) {
        $formattedOutput .= '<span class="'.$fontcolor['vowels'].'">'.$char.'</span>';
    } elseif (in_array($lowercase, $consonants, true)) {
        $formattedOutput .= '<span class="'.$fontcolor['consonants'].'">'.$char.'</span>';
    } else {
        $formattedOutput .= $char;
    }
}

echo nl2br($formattedOutput);

推荐阅读