带有preg_replace的PHP正则表达式和“。”字符

时间:2012-03-04 15:46:38

标签: php regex preg-replace

我的科学名称有以下格式:

S. daemon
A. cacatuoides
B. splendens

Etc等。

我对“。”有困难。字符。

此代码适用于完整物种名称(即Satanoperca daemon):

  foreach ($species as $term) {
    $term_norm = preg_replace('/\s+/', ' ', strtoupper(trim($term)));
    $pattern[] = preg_replace('/ /', '\\s+', preg_quote($term_norm));

    $urls[$term_norm] = '/dev/species/' . str_replace(" ", "-", rawurlencode($term));
    $rels[$term_norm] = $urls[$term_norm] . '?preview=true';
    $title[$term_norm] = $term;

但我无法让它适用于上述例子:

    $genus_species = explode(" ", $term);
    $genus = $genus_species[0];
    $species = $genus_species[1];
    $initial = substr($genus, 0, 1);
    $shortened = $initial . '. ' . $species;

    $term_norm = preg_replace('/\s+/', ' ', strtoupper(trim($shortened)));
    $pattern[] = preg_replace('/ /', '\\s+', preg_quote($term_norm));

    $urls[$term_norm] = '/dev/species/' . rawurlencode($term);
    $rels[$term_norm] = $urls[$term_norm] . '?preview=true';
    $title[$term_norm] = $term;

如果我使用此代码,几乎所有的源代码,即每个单词/字符,都与<a href=""></a>链接。如果我对代码进行注释,则全名链接可以完美地工作,而不会出现这样的问题。


多一点信息......

$pattern呼应:/\b(SATANOPERCA\s+DAEMON|S(\.)\s+DAEMON)\b/i

输入是一个物种名称列表,例如我之前提到的那些。来源是物种概况,通常指其他物种。

我希望代码要做的是将这些物种名称的任何提及替换为该物种概况的链接。


提前致谢,

2 个答案:

答案 0 :(得分:1)

在调查您的问题时,我遇到了您最初构建正则表达式的方式。我想,为什么不简化呢?以下是我的想法:

foreach ($terms as $term) {
    list($genus, $species) = explode(' ', $term);
    $pattern = sprintf('~\b((?:%s[.]|%s) %s)~i', $genus[0], $genus, $species);

以下是

~\b((?:S[.]|Satanoperca) daemon)~i

我在这里结合使用listexplode相结合,通常代码较少,因此更易读。

要构建正则表达式,我使用sprintf,这通常更容易形成需要替换的复杂字符串。它允许使用掩码。

最后$genus[0]$genus的第一个字符。如果您使用的是多字节字符集,则可能需要替换它。只是说。

模式本身也是简化的:

~\b((?:S[.]|Satanoperca) daemon)~i

第一个子组是非捕获的(?:)并提供两种变体:短.或长属。然后是空间,最后是物种。我也使用[.]来表达那里的点,但确保\.也可以使用:

~\b((?:S\.|Satanoperca) daemon)~i

剩下的是更换程序。我选择在这里使用回调函数。因为链接只需要为术语构建一次,所以我在foreach之上添加它。我再次使用sprintf格式化它:

foreach ($terms as $term) {
    $termSlug = strtolower(strtr($term, array(' ' => '-')));
    $termHref = sprintf('/dev/species/%s', rawurlencode($termSlug));
    list($genus, $species) = explode(' ', $term);
    $pattern = sprintf('~\b((?:%s\.|%s) %s)~i', $genus[0], $genus, $species);

剩下的是使用链接替换每个匹配的回调函数:

    $string = preg_replace_callback($pattern, function($match) use($term, $termHref)
    {
        return sprintf('<a href="%s" title="%s">%s</a>', $termHref
            , htmlspecialchars($term), htmlspecialchars($match[1]));
    }, $string);

就是这样。完整的例子:

$string = <<<STR
S. daemon
Satanoperca daemon
A. cacatuoides
B. splendens
STR;

$terms = array(
    'Satanoperca daemon',
);

foreach ($terms as $term) {
    $termSlug = strtolower(strtr($term, array(' ' => '-')));
    $termHref = sprintf('/dev/species/%s', rawurlencode($termSlug));
    list($genus, $species) = explode(' ', $term);
    $pattern = sprintf('~\b((?:%s\.|%s) %s)~i', $genus[0], $genus, $species);
    echo $pattern, "\n";
    $string = preg_replace_callback($pattern, function($match) use($term, $termHref)
    {
        return sprintf('<a href="%s" title="%s">%s</a>', $termHref
            , htmlspecialchars($term), htmlspecialchars($match[1]));
    }, $string);
}

echo $string;

它的输出:

<a href="/dev/species/satanoperca-daemon" title="Satanoperca daemon">S. daemon</a>
<a href="/dev/species/satanoperca-daemon" title="Satanoperca daemon">Satanoperca daemon</a>
A. cacatuoides
B. splendens

我希望这有用,即使它是全新的代码。


验证条款:

// validate terms
$valid = '/^\w+ \w+$/';
foreach ($terms as $index => $term) {
    if ($result = preg_match($valid, $term))
        continue;
    printf("Invalid Term: (%d) %s\n", $index, $term);
}

答案 1 :(得分:0)

您是否也希望将.也包括在内

$term_norm = preg_replace('/[\s\.]+/', ' ', strtoupper(trim($shortened)));