如何编写模式以获取带有文本描述的组合单词?

时间:2018-05-24 15:11:20

标签: php regex utf-8

我有示例文本:

$text = "
АДАБГОЊ љои адаб-
омўзї.
АДАБДОН ادبدان ошно бо адабу фарњанг.
тиллову нуќра бо мањак ва ѓ.; зар(р)и иёр тил-
лои холис.
АЁРА اياره 1. ёра, дастбиранљан.
";

我有一个示例代码,用于将大写单词转换为数组键,并将数组值转换为大写单词的所有文本:

$regex = '~\b-(?:\R|\h)\b~u';
$text = preg_replace($regex, '', $text);
$pattern = '~^(\p{Lu}+)\h+(.*(?:\R(?!\p{Lu}+\h).*)*)~mu';
preg_match_all($pattern, $text, $matches);
$result = array_combine(array_map('mb_strtolower', $matches[1]), preg_replace('~\s*\R++\s*~u', ' ', preg_replace('~\p{Arabic}+~u', '', $matches[2])));
echo "<pre>";
print_r($result);
echo "</pre>";

结果exec代码:

Array
(
    [адабгоњ] => љои адабомўзї. 
    [адабдон] =>  ошно бо адабу фарњанг. тиллову нуќра бо мањак ва ѓ.; зар(р)и иёр тиллои холис. 
    [аёра] =>  1. ёра, дастбиранљан. 
)

但我有第二种类型的文字,我有问题:

$text = "
АДАБГОЊ//АДАБГАЊ ادبگه//ادبگاه љои адаб-
омўзї.
АДАБДОН ادبدان ошно бо адабу фарњанг.
АЁЃ//АЁЌ т. اياق//اياغ кит. пиёла, ќадањ, соѓар.
АЁР//ИЁР а. ايار санљидани дараљаи холисияти
тиллову нуќра бо мањак ва ѓ.; зар(р)и иёр тил-
лои холис.
АЁРА اياره 1. ёра, дастбиранљан.
АДУ//АДУВ а. عدو ниг. адў.
";

在这种类型的文字中,我有带符号//的单词。这种类型用一个描述来说两个单词。 (WORD // WORD描述)。当我使用旧代码时,结果将是:

Array
(
    [адабдон] =>  ошно бо адабу фарњанг. АЁЃ//АЁЌ т. // кит. пиёла, ќадањ, соѓар. АЁР//ИЁР а.  санљидани дараљаи холисияти тиллову нуќра бо мањак ва ѓ.; зар(р)и иёр тиллои холис. 
    [аёра] =>  1. ёра, дастбиранљан. АДУ//АДУВ а.  ниг. адў. 
)

如何编写模式以获取样本结果:

Array
(
    [адабдон] =>  ошно бо адабу фарњанг. 
    [аёѓ] => т. // кит. пиёла, ќадањ, соѓар. 
    [аёк] => т. // кит. пиёла, ќадањ, соѓар.
    [аёр] => а.  санљидани дараљаи холисияти тиллову нуќра бо мањак ва ѓ.; зар(р)и иёр тиллои холис. 
    [иёр] => а.  санљидани дараљаи холисияти тиллову нуќра бо мањак ва ѓ.; зар(р)и иёр тиллои холис. 
    [аёра] =>  1. ёра, дастбиранљан.
    [аду] =>  а.  ниг. адў. 
    [адув] =>  а.  ниг. адў. 
)

此处所有带有//符号的字词都保存了一个描述。

1 个答案:

答案 0 :(得分:1)

使用preg_split的方式:

$text = "
АДАБГОЊ//АДАБГАЊ ادبگه//ادبگاه љои адаб-
омўзї.
АДАБДОН ادبدان ошно бо адабу фарњанг.
АЁЃ//АЁЌ т. اياق//اياغ кит. пиёла, ќадањ, соѓар.
АЁР//ИЁР а. ايار санљидани дараљаи холисияти
тиллову нуќра бо мањак ва ѓ.; зар(р)и иёр тил-
лои холис.
АЁРА اياره 1. ёра, дастбиранљан.
АДУ//АДУВ а. عدو ниг. адў.
";

$defs = preg_split('~^(\p{Lu}+(?://\p{Lu}+)*)\h+~mu', trim($text), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

$result = [];
while ( false !== $items = current($defs) ) {
    $def = trim(preg_replace('~(?:\s*\p{Arabic}+(?://\p{Arabic}+)*)?\s+~u', ' ', next($defs)));
    foreach (explode('//', $items) as $item) {
        $result[$item] = $def;
    }
    next($defs);
}

print_r($result);

demo

建议:如果文本来自一个非常大的文件,并且您不需要将整个数组放在内存中,则可以使用用户定义的流过滤器重写此代码,并最终生成一个生成键和值的生成器(yield $key => $value;)以节省内存,例如:

class NormalizeFilter extends php_user_filter
{
    public function filter($in, $out, &$consumed, $closing)
    {
        while ($bucket = stream_bucket_make_writeable($in)) {
            $bucket->data = preg_replace('~\s+\p{Arabic}*(?://\p{Arabic}+)*\s*(?!^\p{Lu})~mu', ' ', $bucket->data);
            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON;
    }
}

stream_filter_register("norm", "NormalizeFilter")
    or die("Failed to register filter");

function genDefs($fh, $bufferSize = 1024) {
    while ( false !== $line = fgets($fh, $bufferSize) ) {
        if ( preg_match('~^(\p{Lu}+(?://\p{Lu}+)*) \K.*\S~u', $line, $m) ) {
            foreach ( explode('//', $m[1]) as $item ) {
                yield $item => $m[0];
            }
        }
    }
}

$fh = fopen('php://filter/read=norm/resource=file:///path/to/file.txt', 'r');

$defs = genDefs($fh);

foreach ($defs as $item => $definition) {
    echo "$item: $definition\n";
}

demo
variant