C言語でパソコン甲子園に挑戦(5回戦)

2009 年 7 月 31 日 | カテゴリー: こっそり学ぶC言語

あ~ヤバい、Python楽しいですねPython!!「みんなのPython」をこっそり購入し、webサイトのチュートリアルをインタラクティブシェルとかいうので試してワァワァ喜んでいます(= ‘艸’)ムププ

「いやテメー、今年はC言語勉強するんじゃなかったのかよ!?」というツッコミをかわす為ではありませんが、基礎の習得を目指して今回は「2006年本選 問題07」に挑戦してみました。

コンソールから入力された文字列(ヘビ)を解析して、どのパターンに当てはまるかを表示する、ってコレ、まんま正規表現ですよね。

C言語には正規表現が無い!!と思っていたのですが、エントリを書きながら調べたら「regex.h」とかいうのがあるそうです。うぅぅ、調べるのが遅すぎました(。□。;)

で、問題集には「状態遷移図」を書いてチャレンジしてみるのも楽しいよ!!と書いてあったので、状態遷移図を調べていたら頭から煙がプスプスと…(゚_。)?

なので、思いっきり力技で比較してみました~。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NUM 10000
#define TYPE_A 0
#define TYPE_B 1
#define TYPE_NA 2

int check_snake_a(char str[], int len);
int check_snake_b(char str[], int len);

int main(void)
{
  int i, len, num, p[MAX_NUM];
  char snake[100];
  char *ans[3] = {"A", "B", "NA"};

  printf("何匹のヘビを判定しますか?\n");
  scanf("%d", &num);
  if (MAX_NUM < num) {
    printf("判定出来るヘビは10,000匹までです\n");
    exit(1);
  }

  i = 0;
  do {
    scanf("%100s", snake);
    len = strlen(snake);

    /* 頭のパターンを判別 */
    if (0 == strncmp(snake, ">'", 2)) {
      p[i] = check_snake_a(snake, len);
    } else if (0 == strncmp(snake, ">^", 2)) {
      p[i] = check_snake_b(snake, len);
    } else {
      p[i] = TYPE_NA;
    }
    i++;
  } while (i < num);

  /* 入力された順に判定結果を表示 */
  for (i = 0; i < num; i++) {
    printf("%s\n", ans[p[i]]);
  }

  return 0;
}

int check_snake_a(char str[], int len)
{
  int i, cntL, cntR, center;

  /* 先に末尾をチェック */
  if (str[len - 1] != '~') {
    return TYPE_NA;
  }
  /* 胴体パターンのチェック */
  i = 2;
  cntL = 0;
  cntR = 0;
  center = 0;
  while (i < (len - 2)) {
    /* "#"の出現を判定 */
    if (str[i] == '#') {
      center = i;
      break;
    }
    i++;
  }
  if (center == 0 || i == 2) {
    return TYPE_NA;
  }
  /* "#"の左側をチェック */
  for (i = 2; i < center; i++) {
    if (str[i] != '=') {
      return TYPE_NA;
    }
    /* "="の出現回数をカウント */
    cntL++;
  }
  if (! cntL) return TYPE_NA;

  /* "#"の右側をチェック */
  for (i = center + 1; i < len - 1; i++) {
    if (str[i] != '=') {
      return TYPE_NA;
    }
    /* "="の出現回数をカウント */
    cntR++;
  }
  if (! cntR) return TYPE_NA;

  /* 左右の出現回数を判定 */
  if (cntL == cntR)
    return TYPE_A;
  else
    return TYPE_NA;
}

int check_snake_b(char str[], int len)
{
  int i;

  /* 先に末尾をチェック */
  if (str[len - 1] != '~' && str[len - 2] != '~') {
    return TYPE_NA;
  }
  /* 胴体パターンのチェック */
  i = 2;
  while (i < (len - 4)) {
    /* "Q="にマッチするか判定 */
    if (str[i] == 'Q' && str[i + 1] == '=') {
      i += 2;
      continue;
    } else {
      return TYPE_NA;
    }
  }

  return TYPE_B;
}

う~ん、サンプル解答とまるで違うのですが一応判別はちゃんと行っています。どうなんでしょう??本当は、結果を格納するint型の配列変数pを動的に確保したかったのですが、malloc()関数がよく理解出来ず、代替行為としてメモリを思い切り無駄遣いしております(*´σー`)

スパゲッティコードをガッチリ晒したついでに、正規表現といえばPHPの守備範囲という事で、以下PHPのコードです。

<?php
// 標準入力からの引数チェック
if ($argc !== 2) {
  exit("Usage: ./snake.php SNAKE_PATTERN\n");
}

// 入力された文字列の制限チェック
$snake = $argv[1];
if (100 < strlen($snake) || FALSE !== strpos(' ', $snake)) {
  exit("Snake pattern is no longer than 100 and whitespace is not allowed\n");
}

// 正規表現パターン
$snakeA = '/>\'(=+)?#\1~$/';
$snakeB = '/>\^(Q=)+?~~$/';

// パターンの判別
if (preg_match($snakeA, $snake)) {
  echo "A\n";
} elseif (preg_match($snakeB, $snake)) {
  echo "B\n";
} else {
  echo "NA\n";
}
/**
 * End of file snake.php
 */

こうして比較すると、パターンを記述するのにいつもウンウン唸ってる正規表現が、このうえなく便利なものであると実感出来ますね。

ちなみに、パターン内部での後方参照には”$n”という形式は使えず、”\n”で参照するらしいです。知らずにハマったのはいつもの事…。

では、この勢い(?)で張り切って6回戦に挑戦したいと思います!!けど、Pythonも楽しいし、本職エンジニアのpazサンのブログを拝見してるとシェルスクリプトももっと上達したいし。モチロン、PHPももっと美しいコードを書けるようになりたいし…。う~ん、悩ましいです^^

今日はここまでヾ(*’-'*)マタネー♪

コメントはまだありません。