php - 在 PHP 中拆分、计数和格式化多字节字符
问题描述
我正在构建一个实验性的 PHP 应用程序,用于处理Cyrillic UTF-8 characters 中的诗歌。我想实现以下目标:
- 计算每个字符的出现次数和“所有辅音”等类别的总计数。它可能包括特殊字符和标点符号,只要我可以在输出中隐藏其中一些。我使用 UTF-8,所以我只能使用多字节函数。不可能使用 count_chars() :(
- 保留换行符和大写。我保留了具有不同格式的原始文本的多个副本。它们可能看起来多余,但我想尽可能多地保留信息。
- 根据条件更改某些字符的 HTML 格式,例如为元音和辅音提供不同的背景颜色,或突出显示所选字符的每个出现。据我了解,首先我需要将我的字符串分成几行(以保留中断),然后将它们中的每一个转换为一个包含 1 个字符的块的数组。对于输出,我将 join() 行返回。不幸的是,我找不到任何关于如何将 HTML 应用于数组值来解决像我这样的问题的想法。
我试过的
除了不知道该怎么做之外,我还遇到了一些小问题。这是我现在做的一步一步。
我通过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");
解决方案
如果你想计算文本中元音和辅音的出现次数,你应该计算每个字母的出现次数,然后检查它是元音还是辅音。
要将字符串拆分为字符数组,您应该使用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);
推荐阅读
- node.js - 如何在服务器上的 express 和 node 中创建文件,然后将其下载到我的客户端。我正在为我的前端和后端使用 NextJS
- python - 如何创建更具活力的 Scrapy Spider?
- javascript - 在循环中声明的 React js 函数包含对“允许”变量的不安全引用
- git - 有没有办法对存储库中的各个组件进行版本/标记?
- angular - 直接从 Angular 连接到 Firebase 数据库是否安全?
- swift - 如何为 KCFloatingActionButton 定义 touchUpInside 动作?
- c - 用 fork 创建 num 个进程,然后删除一些我不会使用的进程
- python - 有一个错误需要解密一个整数
- javascript - 使用 Reactjs 的点表示法与括号表示法
- r - 查找值为零的行并在其前后添加行数