C++で大文字小文字を区別しない置き換え+α

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

C++で大文字小文字を区別しない置き換え+α

#1

投稿記事 by fabersid » 5年前

あるプログラムを作っています。
そのプログラム内では禁止用語が設定されています。
その際必要となるのが元の文字列の大文字小文字を区別しない置き換えです。
ただし置き換えるところ以外の大文字小文字はそのままでないといけないです。
どのように組めばいいでしょうか?

禁止用語一覧は指定されたフォルダに
WORD1
WORD2

のような形式で保存されています。
コンパイラ:Borland C++ 5.5.1 for Win32

現在の禁止用語を****に置き換えるプログラム
*は一致した文字数に応じて増加

コード:

//略
string BadWordDetector(const string,bool setting_mode=true);
//略
string BadWordDetector(const string badword,bool setting_mode){
	if(setting_mode){
		transform (badword.begin(), badword.end(), badword.begin(), tolower);
		system(("type nul > "LOG_DIR"\\WORDS\\"+ badword).c_str());
		return "";
	}else{
		string text=badword;
		transform (text.begin(), text.end(), text.begin(), tolower);
		system("dir /B "LOG_DIR"\\WORDS\\");
		ifstream ifs("test.txt");
		string str;
		
		while (getline(ifs, str)){
			string retStr = "";
			badword = //間違ってJavaのコードを書いていたため考え中
		}
		return badword;
	}
}

アバター
usao
記事: 1887
登録日時: 11年前

Re: C++で大文字小文字を区別しない置き換え+α

#2

投稿記事 by usao » 5年前

置き換える場所を探す作業は,大文字(あるいは小文字)の世界で行い,
置き換えは作業は元の文字列をベースにして行えばよいのではないでしょうか.

(雰囲気コード)

コード:

//引数を全て大文字化した文字列を返す
inline std::string ToUpper( const std::string &Src )
{
    std::string Ret = Src;
    std::transform( std::begin(Ret), std::end(Ret), std::begin(Ret), toupper );
    return Ret;
}

//Srcの中で,BadWordの部分を '*'に置き換える.
//検索は,大文字小文字の区別なく行われる.
std::string ReplaceBadWord( const std::string &Src, const std::string &BadWord )
{
    std::string Result = Src;   //結果生成用バッファ
    const std::string SrcUpper = ToUpper( Src );
    const std::string WordUpper = ToUpper( BadWord );

    const auto WordSize = WordUpper.size();

    std::string::size_type offset = 0;
    while( offset < SrcUpper.size() )
    {
        auto FoundPos = SrcUpper.find( WordUpper, offset );
        if( FoundPos == std::string::npos )break;

        for( std::string::size_type i=0; i<WordSize; ++i )
        {   Result[ FoundPos+i ] = '*'; }

        offset = FoundPos + WordUpper.size();
    }

    return Result;
}

アバター
usao
記事: 1887
登録日時: 11年前

Re: C++で大文字小文字を区別しない置き換え+α

#3

投稿記事 by usao » 5年前

わざわざ変数WordSizeがあるんだから

offset = FoundPos + WordUpper.size();
 ↓
offset = FoundPos + WordSize;

ですね.

かずま

Re: C++で大文字小文字を区別しない置き換え+α

#4

投稿記事 by かずま » 5年前

fabersid さんが書きました:
5年前
禁止用語一覧は指定されたフォルダに
WORD1
WORD2

のような形式で保存されています。
指定されたフォルダに、複数のファイルがあり、
そのファイル名が禁止用語ということでしょうか?

指定したファイルに、複数の禁止用語が入っているのが
普通だと思うんですが、そうではないのですね。

Windows で、あるフォルダにあるファイル名をすべて取得するには
FindFirstFile, FindNextFile, FindClose という API を使います。

例えば、c:/tmp/prohibited に、
bitch と shit というファイルがあるとき

コード:

#include <windows.h>
#include <stdio.h>

int main()
{
	WIN32_FIND_DATA fd;
	HANDLE h = FindFirstFile("c:/tmp/prohibited/*", &fd);
	if (h != INVALID_HANDLE_VALUE) {
		do {
			if (fd.cFileName[0] != '.') puts(fd.cFileName);
		} while (FindNextFile(h,&fd));
		FindClose(h);
	}
}
実行結果

コード:

bitch
shit

fabersid
記事: 42
登録日時: 6年前

Re: C++で大文字小文字を区別しない置き換え+α

#5

投稿記事 by fabersid » 5年前

usao さんへ
文字列置き換えプログラムありがとうございます。
文字列を2種類用意する発想はありませんでした。
ありがとうございます。

かずま さんへ
かずま さんが書きました:指定したファイルに、複数の禁止用語が入っているのが
普通だと思うんですが、そうではないのですね。
すみません、その発想がなかっただけです。
わがままだとは思いますができればそちらでお願いします。
もしファイルにまとめるなら改行区切りの予定
教えていただいたAPIは別の関数で使わせていただきます。
(調べて見つけられなかったなんて言えない)

かずま

Re: C++で大文字小文字を区別しない置き換え+α

#6

投稿記事 by かずま » 5年前

最初のプログラムの
 system("dir /B "LOG_DIR"\\WORDS\\");
は、何をしたかったんですか?

とりあえずプログラムを書いてみましたが、理解できますか?
これを参考にあなた自身のプログラムを書いて見せてください。

コード:

#include <iostream>   // cout, endl
#include <fstream>    // ifstream
#include <string>     // getline
#include <cctype>     // toupper
#include <vector>     // vector
#include <algorithm>  // fill
using namespace std;

void replace_word(string& line, const string& word)
{
	string str = line;
	for (int i = 0; i < str.size(); i++)
		str[i] = toupper((unsigned char)str[i]);
	for (size_t i = 0, j, k = word.size();
			(j = str.find(word, i)) != string::npos; i = j + k)
		fill(&line[j], &line[j+k], '*');
}

void replace_words(string& line, const vector<string>& words)
{
	for (int i = 0; i < words.size(); i++)
		replace_word(line, words[i]);
}

int main()
{
	ifstream ifs("c:/tmp/dir/prohibited.txt");
	if (!ifs) return 1;
	vector<string> words;
	string line;
	while (getline(ifs, line)) {
		for (int i = 0; i < line.size(); i++)
			line[i] = toupper((unsigned char)line[i]);
		words.push_back(line);
	}
	ifstream ifs2("c:/tmp/dir/test.txt");
	if (!ifs2) return 2;
	while (getline(ifs2, line)) {
		replace_words(line, words);
		cout << line << endl;
	}
}
prohibited.txt

コード:

Bitch
fuck
shit
test.txt

コード:

The words 'shit' and 'bitch' are found in a bad text.
Does bitch mean a female dog?
What does shit mean?
実行結果

コード:

The words '****' and '*****' are found in a bad text.
Does ***** mean a female dog?
What does **** mean?

fabersid
記事: 42
登録日時: 6年前

Re: C++で大文字小文字を区別しない置き換え+α

#7

投稿記事 by fabersid » 5年前

かずま さんが書きました:
5年前
最初のプログラムの
 system("dir /B "LOG_DIR"\\WORDS\\");
は、何をしたかったんですか?

とりあえずプログラムを書いてみましたが、理解できますか?
テスト用に記入しそのコードから完成まで導く予定でしたが、
行き詰ったのでそのままになったところです。
正直忘れてました。
vector<string>がstringの配列みたいなものを
表しているのであれば理解できたと思います。

作っていたプログラムの全体です
投稿用に少し修正を入れましたが...
.dllの理由はファイルを直接開かれたときにワンクッション置くためです
特に意味はないです。
あまり綺麗なコードではないと思います

コード:

#define DEBUG               0
#define KEY                 0 //会話内容の簡易暗号化キー
#define isADMIN (string(comName)=="ADMIN"?"*":"") //ADMINのところに管理者のコンピューター名
#define WIN32_LEAN_AND_MEAN		  // Windows ヘッダーから使用されていない部分を除外します。
#if DEBUG==1
	#define LOG_DIR         "DATA"
#else
	#define LOG_DIR         "DATA.{BB06C0E4-D293-4f75-8A90-CB05B6477EEE}"
#endif
#define LOG_FILE            LOG_DIR"\\LOG.dll"
#define LOG_USER            LOG_DIR"\\USER.dll"
#define cmd_md(x) system("md "x" > NUL 2>&1")
//define DATA FILEs
/*
DATA.{BB06C0E4-D293-4f75-8A90-CB05B6477EEE}
  LOG.dll
  USERS
    (usernames)
  BADWORDS.dll
*/

#include <algorithm>  // fill
#include <cctype>     // toupper
#include <direct.h>   //フォルダの作成(_mkdir)
#include <fstream>    // ifstream ファイル入出力
#include <iostream>   //標準入出力(C++)
#include <iostream>   // cout, endl
#include <stdio.h>
#include <stdlib.h>   //標準ライブラリ…system()
#include <string>     // getline  ヘッダファイルインクルード
#include <sys\stat.h> //フォルダの確認(stat)
#include <vector>     // vector
#include <windows.h>

using namespace std;	//名前空間指定

int normal(void);
int spectator(void);
int log_import(const string);
int log_export(const string);
int user_log(const string,int in_room=-1);
void BadWordDetector(string&,bool setting_mode=true);
bool command(const string);
bool checkUserExistence(string);
void add_file(const string);
void display_file();
string ango(const string);
bool canUseName(const string);
void help(const string);

char comName[256]="";
int main(int argc, char* argv[]) {
	#define ismode(a,b) if(string(argv[1])!="/"a)b()
	if(2==argc){
		ismode("0",normal);
		ismode("user",normal);
		ismode("1",spectator);
		ismode("show",spectator);
	}
	#undef ismode
	normal();
}
bool canUseName(const string user){
	#define nameErr(x) if(user.find(x)!=string::npos)return false
		nameErr('\\');
		nameErr('/');
		nameErr(':');
		nameErr('*');
		nameErr('?');
		nameErr('\"');
		nameErr('<');
		nameErr('>');
		nameErr('|');
	#undef nameErr
	return true;
}
int normal(){
	DWORD len=sizeof(comName);
	GetComputerName(comName,&len);

	string text="";
	string ango;
	string user;

	do{
		user="";
		cerr << "ユーザー名を入力:";
		cin >> user;
		if(user.find('*')!=string::npos)
			cerr<< "末尾の*はスレ主だけに自動で付けられます。" << endl;
	}while(!canUseName(user)||checkUserExistence(user));
	struct stat statBuf;
	cmd_md(LOG_DIR);
	cmd_md(LOG_DIR"\\USERS");
	
	const char * consoleName = "退室するときはEXITと打ってください。";
	cout << consoleName;
	Sleep(2000);
	SetConsoleTitle(consoleName);
	Sleep(50);
	HWND hWnd = FindWindowA(NULL, consoleName);
	if(hWnd){
		HMENU hMenu = GetSystemMenu(hWnd, FALSE);
		RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
		SetConsoleCtrlHandler(NULL , TRUE);
	}else{
		// printf("%s\n", "失敗");
	}
	
	add_file(user + isADMIN+"さんが入室しました。");
	user_log(user,0);
	while("EXIT"!=text){
		if(!checkUserExistence(user)){
			cout<<"送信に失敗しました\nあなたはキックされています"<<endl;
			user_log(user,2);
			Sleep(3000);
			return 0;
		}
		if(text!=""){
			if(!command(text)){
				BadWordDetector(text,false);
				add_file(user+isADMIN+">>"+text);
			}
		}
		display_file();
		cerr << user << isADMIN << ">>";
		getline(cin, text);
	}
	add_file(user + isADMIN+"さんが退室しました。");
	user_log(user,1);
	exit(0);
	return 1;
}
int spectator(){
	DWORD len=sizeof(comName);
	GetComputerName(comName,&len);
	string text="";

	while("EXIT"!=text){
		if(text!=""&&isADMIN=="*"){
			command(text);
		}
		display_file();
		if(isADMIN=="*"){
			cerr << "spectator(*不可視*)>>";
			getline(cin, text);
		}
	}
	exit(0);
	return 1;
}

void add_file(const string a){
	if(a=="")return;
	ofstream ofs(LOG_FILE,ios::binary|ios::app);
	ofs << ango(a + "\r\n");
	ofs.close();
}

void display_file(){
	system("cls");
	ifstream ifs(LOG_FILE,ios::binary);
	if(!ifs){ return; } //ファイルが開けたか確認
	char buf[256+1]; //256バイトと '\0 'の分のバッファ
	while(!ifs.eof()){
		ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
		buf[ifs.gcount()] = '\0';
		cout << ango(buf); //標準出力に出力してみる
	}
	ifs.close();
}

string ango(const string tmp){
	string ret=tmp;
	for(int i = 0; i < (int)ret.size(); ++i){
		ret[i] = ret[i] ^ KEY;
	}
	return ret;
}

//https://qiita.com/takahiro_itazuri/items/e999ae24ab34b2756b04
bool checkUserExistence(string user){
	ifstream ifs((LOG_DIR"\\Users\\"+user).c_str());
	return ifs.is_open();
}
bool row_delete(const string rowS){
	int rowI = atoi(rowS.c_str());
	ifstream fin;       //テキストファイル入力用ストリーム
	fin.open(LOG_FILE);
	if(fin.fail()){
		cout << "fin.open() failed." << endl;
		return false;
	}
 
	ofstream fout;			 //	 テキストファイル出力用ストリーム
	fout.open(LOG_FILE".tmp");
	if(fout.fail()){
		cout << "fout.open() failed." << endl;
		return false;
	}
 
	string str;
	int id = 0;
	while(true){
		fin >> str;
		if (fin.fail()) break;				   //	 ファイルを最後まで読み込んだ
		id++;
		if(id!=rowI)fout << (id++) << ": " << str << endl;
	}
	fin.close();
	fout.close();
	system(("COPY "+string(LOG_FILE)+".tmp "+string(LOG_FILE)+" /Y").c_str());
	if( remove((LOG_FILE+string(".tmp")).c_str()) == 0 ){
		cerr << LOG_FILE << ".tmpファイルを削除しました" << endl;
	}else{
		cerr << "ファイル削除に失敗しました" << endl;
	}
	return 0;
}

bool command(const string text){
	#define cmd_exec(x,y) {if(text.substr(0,strlen(x))==x){y(text.substr(strlen(x)));return true;}}
		//x=string y=function
		if(isADMIN=="*"||DEBUG==1){
			cmd_exec("/kick ",user_log);
			cmd_exec("/row_del ",row_delete);
			cmd_exec("/import",log_import);
			cmd_exec("/badword ",BadWordDetector);
		}
		cmd_exec("/export",log_export);
		cmd_exec("/help",help);
	#undef cmd_exec
	return false;
}
void help(const string dummy){
	if(isADMIN=="*"||DEBUG==1){
		cout 
			<< "/kick ユーザー名\n"
			<< "ユーザーをtext.exeから追放します。(スレ主権限必須)\n"
			<< "/row_del 行数\n"
			<< "指定された行を削除する。(スレ主権限必須)\n"
			<< "/import\n"
			<< "ファイルを読み込みます。(スレ主権限必須)\n"
			<< "/badword\n"
			<< "Add to the bad word list.(スレ主権限必須・Published in ver.7)\n";
	}
	cout
		<< "/help\n"
		<< "この画面が表示されます。\n"
		<< "/export\n"
		<< "ファイルを平文出力します。\n"
		<< "EXIT\n"
		<< "投稿を終了します。\n\n";
	system("pause");
}

int log_export(const string dummy){
	system("echo D|xcopy "LOG_DIR" "LOG_DIR"_export /E /I /Y>nul");
	ifstream ifs(LOG_DIR"_export\\LOG.dll",ios::binary);
	if(!ifs){ return 1; } //ファイルが開けたか確認
	ofstream ofs(LOG_DIR"_export\\LOG.txt",ios::binary);
	if(!ofs){ ifs.close();return 1; } //ファイルが開けたか確認
	char buf[256+1]; //256バイトと '\0 'の分のバッファ
	while(!ifs.eof()){
		ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
		buf[ifs.gcount()] = '\0';
		ofs << ango(buf); //標準出力に出力してみる
	}
	ifs.close();
	ofs.close();
	system("del "LOG_DIR"_export\\LOG.dll");
	return 0;
}
int log_import(const string dummy){
	system("echo D|xcopy "LOG_DIR"_export "LOG_DIR" /E /I /Y>nul");
	ifstream ifs(LOG_DIR"\\LOG.txt",ios::binary);
	if(!ifs){ return 1; } //ファイルが開けたか確認
	ofstream ofs(LOG_DIR"\\LOG.dll",ios::binary);
	if(!ofs){ ifs.close();return 1; } //ファイルが開けたか確認
	char buf[256+1]; //256バイトと '\0 'の分のバッファ
	while(!ifs.eof()){
		ifs.read(buf,256); //ストリームから256バイトバッファに読み込む
		buf[ifs.gcount()] = '\0';
		ofs << ango(buf); //標準出力に出力してみる
	}
	ifs.close();
	ofs.close();
	system("del"LOG_DIR"_export\\LOG.txt");
	return 0;
}
int user_log(string user,int in_room){
	#define tmp " NAME:"+user+isADMIN+"\tTIME:%date% %time:~0,-3%\tID:"+comName+">> LOG_USER"
	if(in_room==0){
		system(("echo IN   "tmp).c_str());
		system(("type nul > "LOG_DIR"\\USERS\\"+user).c_str());
	}else if(in_room==1){
		system(("echo OUT  "tmp).c_str());
		system(("del "LOG_DIR"\\USERS\\"+user).c_str());
	}else if(in_room==2){
		system(("echo OUT  "tmp).c_str());
	}else if(in_room==-1){
		system(("echo KICK "tmp).c_str());
		system(("del "LOG_DIR"\\USERS\\"+user).c_str());
	}else{
		system(("echo ????"tmp).c_str());
		return 1;
	}
	#undef tmp
	return 0;
}

void replace_word(string& line, const string& word){
	string str = line;
	for (int i = 0; i < str.size(); i++)
		str[i] = toupper((unsigned char)str[i]);
	for (size_t i = 0, j, k = word.size();
			(j = str.find(word, i)) != string::npos; i = j + k)
		fill(&line[j], &line[j+k], '*');
}

void replace_words(string& line, const vector<string>& words){
	for (int i = 0; i < words.size(); i++)
		replace_word(line, words[i]);
}
void BadWordDetector(string& sentence,bool setting_mode){
	if(setting_mode){
		for (int i = 0; i < sentence.size(); i++)
			sentence[i] = toupper((unsigned char)sentence[i]);
		system(("echo "+sentence+">> "LOG_DIR"\\BADWORDS.dll").c_str());
	}else{
		ifstream ifs(LOG_DIR"\\BADWORDS.dll");
		if (!ifs) return;
		vector<string> words;
		string line;
		while (getline(ifs, line)) {
			for (int i = 0; i < line.size(); i++)
				line[i] = toupper((unsigned char)line[i]);
			words.push_back(line);
		}
		replace_words(sentence, words);
	}
}

返信

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