如何将所有单词更改为大写但排除罗马数字?

时间:2014-02-03 14:49:42

标签: php regex

我正在尝试修复一些手动输入的地址。我需要在整个地址上应用ucwords,但我希望将所有罗马数字保留为大写字母,并将字母保留在门牌号码后面。

VIA PIPPO III 74A

应该成为:

Via Pippo III 74A

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:2)

使用negative lookahead查找罗马数字的字词:

/\b(?![LXIVCDM]+\b)([A-Z]+)\b/

说明:

  • \b - 在字边界处断言位置
  • (?! - 负向前瞻
    • [LXIVCDM]+ - 匹配列表中的任何字符一次或多次
    • \b - 在字边界处断言位置
  • ) - 结束否定前瞻
  • [A-Z] - 任何大写字母,一次或多次
  • \b - 在字边界处断言位置

实际上,这匹配任何不是完全的单词由列表[LXIVCDM]中的字符组成 - 也就是说,它匹配任何不是罗马数字的单词。

Regex101 Demo


现在,使用preg_replace_callback()捕获这些单词,将它们转换为小写,然后将第一个字母大写:

$input = 'VIA PIPPO III 74A';    
$pattern = '/\b(?![LXIVCDM]+\b)([A-Z]+)\b/';

$output = preg_replace_callback($pattern, function($matches) {
    return ucfirst(strtolower($matches[0]));
}, $input);

var_dump($output);

输出:

string(17) "Via Pippo III 74A"

Demo

答案 1 :(得分:0)

通过mb_eregi_replace()

选择性地大写字符串的大写部分
$str = mb_eregi_replace('\b([0-9]{1,4}[a-z]{1,2})\b', "strtoupper('\\1')", $str, 'e');

完整示例,如何修复手动输入的地址,大写字母的第一个字母并保留大写罗马数字和字母A后面的字母A,B,C):

function ucAddress($str) {

    // first lowercase all and use the default ucwords
    $str = ucwords(strtolower($str));

    // let's fix the default ucwords...
    // uppercase letters after house number (was lowercased by the strtolower above)
    $str = mb_eregi_replace('\b([0-9]{1,4}[a-z]{1,2})\b', "strtoupper('\\1')", $str, 'e');

    // the same for roman numerals
    $str = mb_eregi_replace('\bM{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\b', "strtoupper('\\0')", $str, 'e');

    return $str;
}