文字の一致と、部分一致について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
働かない暇人
記事: 5
登録日時: 4年前

文字の一致と、部分一致について

#1

投稿記事 by 働かない暇人 » 4年前

c言語を始めたばかりの初心者です。
if文で、文字での一致と部分一致がやりたいのですが、
”男”という文字でif文が反応してくれず、プログラムが終わってしまいます。
sexのつく所に[20]を付けたり消したり試しましたがだめでした。。。
どう改善すればいいでしょうか?
あと、部分一致のやり方もお願いします。

一致できない文

コード:

#include <stdio.h>

int main(void)
{
	char sex[20];
	
	printf("性別を入力してください。\n");
	scanf("%s",&sex);
	
	if(sex == "男" )   
	{
		printf("了解\n");
	}
	
	return 0;
	
}

Rittai_3D
記事: 525
登録日時: 7年前

Re: 文字の一致と、部分一致について

#2

投稿記事 by Rittai_3D » 4年前

文字列の比較にはstrcmp()を使用すればよいです。
また部分一致にはstrncmp()を使用すればよいと思います。
初心者です

アバター
usao
記事: 1584
登録日時: 7年前

Re: 文字の一致と、部分一致について

#3

投稿記事 by usao » 4年前

>scanf("%s",&sex);

ここもだめかと.

アバター
みけCAT
記事: 6274
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 文字の一致と、部分一致について

#4

投稿記事 by みけCAT » 4年前

コード:

scanf("%19s",sex); /* 正しい。読み込む文字列の最大の長さ(領域の大きさ-終端の分1文字)を指定することで、バッファオーバーランのリスクを減らしている */
scanf("%s",sex); /* 間違っていない。バッファオーバーランのリスクがあるが、仕様内の入力なら問題ない */
scanf("%s",&sex); /* 間違い。警告が出ることがあるし、未定義動作になりそうな気がする[要出典]が、動いてしまうことが多い */
scanf("%s",sex[20]); /* 大間違い。確保した領域の範囲外にアクセスしているし、ポインタとして無効な値が渡されるのでアクセス違反で強制終了になる可能性が高い */
scanf("%s",&sex[20]); /* 大間違い。確保した領域の範囲外にアクセスしている上、アクセス違反が出ないことがあるのでたちが悪い */
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6274
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 文字の一致と、部分一致について

#5

投稿記事 by みけCAT » 4年前

働かない暇人 さんが書きました:あと、部分一致のやり方もお願いします。
「部分一致」とは具体的にどういう処理でしょうか?
strstr()関数が使えるかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

通しすがりの猫

Re: 文字の一致と、部分一致について

#6

投稿記事 by 通しすがりの猫 » 4年前

C++で日本語いじった事ないので、参考にだけしてください。

まずC++はカジュアルな文字列処理にはイマイチ向いていません。
うろ覚えですが、C++には文字列という概念がなく、全てをbit sequenceとして扱います。
従って、file encodingとかcompiler parameterとかを基に、コード内の文字列はbit sequenceに変換されて、ハードコードされた数字としてプログラム内部に格納されます。

コンソールから入力がある場合、windows日本語環境だとcp932というencodingで確か入力がされるんですが、cp932は日本語の全文字種をカヴァーしてないんですよね(あとencodingは幾つもあります)。

一方utf-8を使うと、ウィンドウズのdos promptが文句を言います。さらにutf-8は一つの文字を1byteから4byes(1charから4char)の可変長のメモリー領域を使って表現する規格なので、program内部でutf-8からutf-16に変換して、其々の文字にmy_str[6]のようの形でアクセスで来るようにしないと面倒です(一つの文字の四分の一だけ取得しても使いようが有りません)。

どれも大した事ではないんですが、塵も積もればで面倒です。Linuxだとマシですが、面倒なのは同じです。
外部ライブラリーを使わずに日本語処理をするのは、趣味以外では避けたほうが無難です。貴方が初心者で、文字列処理がしたいなら、pythonかルビーを覚えましょう。どうしてもC++でやりたければ、ライブラリーを探しましょう。
基礎を勉強している段階ではANSI character以外の使用はお薦めできません。

恥ずかしくて見せたくないものですが、勉強用に昔触った時に拾ったり書いたりしたencoding変換用のコードです(Mecab用だったのでsmart_ptrもRAIIも無しの汚いコードですが):

コード:

#ifndef ECONV
#define ECONV
#include <iostream>
#include <string>
#include <Windows.h>//has kernel32.dll, WideCharToMultiByte

using namespace std;
//author 
//http://sayahamitt.net/utf8%E3%81%AAstring%E5%85%A5%E3%82%8C%E3%81%9F%E3%82%89shiftjis%E3%81%AAstring%E5%87%BA%E3%81%A6%E3%81%8F%E3%82%8B%E9%96%A2%E6%95%B0%E4%BD%9C%E3%81%A3%E3%81%9F/


std::string utf8ToShistjis(std::string &srcUTF8);
std::string shiftjisToUtf8(std::string& srcSjis);
std::string eucjpToShiftjis(std::string& s);

#endif

コード:

#include "stdafx.h"
#include "EConv.h"
std::string utf8ToShistjis(std::string &srcUTF8){
	//Unicodeへ変換後の文字列長を得る 終端文字を得るために+1

	//srcUTF8.size() + 1 is ok because size does not include
	//the terminating null character but -1 is ok too
	int lenghtUnicode = MultiByteToWideChar(
		CP_UTF8, 0, srcUTF8.c_str(), 
		srcUTF8.size() + 1, NULL, 0);
	//when the last arg is 0, this function returns
	//the number of chars (bytes) needed as a buffer to
	//include up to the terminating null character

		
	//必要な分だけUnicode文字列のバッファを確保
	wchar_t* bufUnicode = new wchar_t[lenghtUnicode];

	//UTF8からUnicodeへ変換 終端文字を得るために+1
	MultiByteToWideChar(
		CP_UTF8, 0, srcUTF8.c_str(), srcUTF8.size() + 1, 
		bufUnicode, lenghtUnicode);

	//ShiftJISへ変換後の文字列長を得る bufUnicodeは終端文字を含む
	int lengthSJis = WideCharToMultiByte(
		CP_THREAD_ACP, 0, bufUnicode, 
		-1, NULL, 0, NULL, NULL);

	//必要な分だけShiftJIS文字列のバッファを確保
	char* bufShiftJis = new char[lengthSJis];

	//UnicodeからUTF8へ変換
	//1: code point, 2:mode of conversion
	//3: pointer to be convereted
	//4: buffer size but -1 for a null terminated string
	//5: buffer into which to write,
	//6: target buffer size, if 0, returns the size buffer should be
	WideCharToMultiByte(
		CP_THREAD_ACP, 0, bufUnicode,lenghtUnicode, 
		bufShiftJis, lengthSJis, NULL, NULL);

	std::string strSJis(bufShiftJis);

	delete [] bufUnicode;
	delete [] bufShiftJis;

	return strSJis;
}


std::string shiftjisToUtf8(std::string &srcSjis){
	int numCharacters = srcSjis.length()+1;
	//Unicodeへ変換後の文字列長を得る

	int lengthUnicode = MultiByteToWideChar(
		CP_THREAD_ACP, 0, srcSjis.c_str(), -1, NULL, 0);
	//when the last arg is 0, this function returns
	//the number of chars (bytes) needed as a buffer
	//to include up to the terminating null character	

	//必要な分だけUnicode文字列のバッファを確保
	wchar_t* bufUnicode = new wchar_t[lengthUnicode];

	//ShiftJISからUnicodeへ変換
	MultiByteToWideChar(
		CP_THREAD_ACP, 0, srcSjis.c_str(), srcSjis.size()+1, 
		bufUnicode, lengthUnicode);


	//UnicodeからUTF8へ変換
	//1: code point, 2:mode of conversion
	//3: pointer to be convereted
	//4: buffer size but -1 for a null terminated string
	//but on windows, not all strings are null terminated
	//5: buffer into which to write,
	//6: target buffer size, if 0, returns the size buffer should be
	int lengthUTF8 = WideCharToMultiByte(
		CP_UTF8, 0, bufUnicode, -1, NULL, 
		0, NULL, NULL);

	//必要な分だけUTF8文字列のバッファを確保
	char* bufUTF8 = new char[lengthUTF8];

	//UnicodeからUTF8へ変換
	//1: code point, 2:mode of conversion
	//3: pointer to be convereted
	//4: buffer size but -1 for a null terminated string
	//5: buffer into which to write,
	//6: target buffer size, if 0, returns the size buffer should be
	WideCharToMultiByte(
		CP_UTF8, 0, bufUnicode, lengthUnicode, bufUTF8, 
		lengthUTF8, NULL, NULL);

	std::string strUTF8(bufUTF8);

	delete [] bufUnicode;
	delete [] bufUTF8;

	return strUTF8;
}

std::string eucjpToShiftjis(std::string &s){
	//from eucjp
	char *c = &s.front();
	int len = strlen(c);
	// get the table, the first bytes fir for columns, 
	//the second for rows
	for (char* it = c; it < c + len; ++it){
		it -= 10;
	}
	for (char*it = c; it < c + len; it += 2){
		//hell, shift-jis requires different calculations
		//for the first and second bytes! And then they are 
		//multiple of 2 and not multiple of 2!!
		*it = (*it < 63) ? (*it / 2) + 129 : (*it / 2) + 177;

		char *sit = it + 1;
		if (!*sit % 2){
			*sit + 224;
		}
		else{
			*sit = (*sit < 63) ? (*sit / 2) + 63 : (*sit / 2) + 64;
		}
	}
	return s;
}
追記:
やったこと無いんで自信はないんですが、c++のchar pointerならキャストしてintやlongとして比較できますよ(でもintやlong, charの長さってplatform毎に違ったかも)。そう言えば、日本語って、8ビットのchar型には収まらなかった気がするので、漢字が何ビットになってるか調べたほうがいいかも。多分漢字がchar2個くらいに分割されて入ってるんじゃないかな。

通しすがりの猫

Re: 文字の一致と、部分一致について

#7

投稿記事 by 通しすがりの猫 » 4年前

Cって見てませんでした、スイマセン。もう寝ます。

naohiro19
記事: 256
登録日時: 9年前
住所: 愛知県

Re: 文字の一致と、部分一致について

#8

投稿記事 by naohiro19 » 4年前

コード:

scanf("%19s%*[^\n]%*c", sex);

コード:

fgets(sex, 20, stdin); 
である必要があります。

働かない暇人
記事: 5
登録日時: 4年前

Re: 文字の一致と、部分一致について

#9

投稿記事 by 働かない暇人 » 4年前

&を除き、strstrを引用したらできました。
皆さんの回答感謝です。。。

閉鎖

“C言語何でも質問掲示板” へ戻る