ページ

2012/09/12

[競技プログラミング][PHP][天下一プログラマーコンテスト2012][AC] camel_case

[競技プログラミング][PHP][天下一プログラマーコンテスト2012]camel_case | DevAchieveの解き直し版。
記事で分かる人教えてくださいってお願いしておいたら本当に教えてくださる方が!感謝です!


回答

AtCoder/tenka1_2012_B_2_preg_replace.php at master · wada811/AtCoder
<?php
$variable = trim(fgets(STDIN));
if(isCamelCase($variable)){
    $variable = toSnakeCase($variable);
}else if(isSnakeCase($variable)){
    $variable = toCamelCase($variable);
}
echo $variable.PHP_EOL;


function isCamelCase($str){
    return preg_match('/^_*[a-z][a-z0-9]*([A-Z][a-z0-9]*)*_*$/', $str, $matches);
}

function toCamelCase($str){
    preg_match('/^(_*).*$/', $str, $matches);
    $str = substr($str, strlen($matches[1]));
    return $matches[1].preg_replace('/_([a-z])/e', 'strtoupper("$1")', $str);
}

function isSnakeCase($str){
    return preg_match('/^_*[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*_*$/', $str, $matches);
}

function toSnakeCase($str){
    return preg_replace('/([A-Z])/e', '"_".strtolower("$1")', $str);
}
?>
AtCoder/tenka1_2012_B_2_preg_replace_callback.php at master · wada811/AtCoder
<?php
$variable = trim(fgets(STDIN));
if(isCamelCase($variable)){
    $variable = toSnakeCase($variable);
}else if(isSnakeCase($variable)){
    $variable = toCamelCase($variable);
}
echo $variable.PHP_EOL;


function isCamelCase($str){
    return preg_match('/^_*[a-z][a-z0-9]*([A-Z][a-z0-9]*)*_*$/', $str, $matches);
}

function toCamelCase($str){
    preg_match('/^(_*).*$/', $str, $matches);
    $str = substr($str, strlen($matches[1]));
    return $matches[1].preg_replace_callback(
        '/_([a-z])/',
        create_function('$matches', 'return strtoupper($matches[1]);'),
        $str);
}

function isSnakeCase($str){
    return preg_match('/^_*[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*_*$/', $str, $matches);
}

function toSnakeCase($str){
    return preg_replace_callback(
        '/([A-Z])/', 
        create_function('$matches', 'return "_".strtolower($matches[1]);'),
        $str);
}
?>
無事に両方通りました。原因としては単語が一文字でもOKだったということ。
ただ、一文字だけの単語を許容しても置換で preg_replace と preg_replace_callback は
_aXYZ0_ を見た際に aX の後は xY ではなく、 YZ を見に行ってしまうので
マッチ方法を変えなければいけませんでした。
判定でガチガチにキャメルケースとスネークケースを判別しているので変換では少し緩めにしました。
キャメルケース → スネークケース の場合は、大文字がマッチした時点で単語の先頭だということになります。
スネークケース → キャメルケース の場合は、先頭に付加されるアンダースコアが判定に影響するので
function toCamelCase($str){
    preg_match('/^(_*).*$/', $str, $matches);
    $str = substr($str, strlen($matches[1]));
    return $matches[1].preg_replace_callback(
        '/_([a-z])/',
        create_function('$matches', 'return strtoupper($matches[1]);'),
        $str);
}
先頭のアンダースコアをマッチさせて除去した後に置換をかけて、
プレフィックスとしてアンダースコアを付加することにしました。

おかげさまで解くことができました。@cielavenirさん、本当にありがとうございました!