본문 바로가기
코드이그나이터와 php7와 mysql

코드이그나이터4. 네이버검색 따라잡기-5. 영타한글 변환 검색

1. 오토셋 APM 인스톨러 ( apache + php7.2 + mariadb ) 설치 | https://itadventure.tistory.com/93

2. 코드이그나이터 4 ( codeigniter 4 ) 설치 | https://itadventure.tistory.com/95

3. 비주얼 스튜디오 코드 에디터 설치 & 한글 설정 | https://itadventure.tistory.com/96

4. 폴더열기 / 웹페이지 편집(1) | https://itadventure.tistory.com/97

5. 웹페이지 편집(2) | https://itadventure.tistory.com/101

6. 코드이그나이터4의 URL 규칙 | https://itadventure.tistory.com/105

7. php, 네임스페이스 [ namespace ] ?! | https://itadventure.tistory.com/118

8. 코드이그나이터의 네임스페이스, 그리고 모델 | https://itadventure.tistory.com/122

9. 코드이그나이터 뷰의 파라미터 전달 | https://itadventure.tistory.com/147

10. 코드이그나이터 뷰를 나눠 볼까요? | https://itadventure.tistory.com/174

11. MYSQL 이 뭐여? [ 마이에스큐엘은 서류철이다! ] | https://itadventure.tistory.com/175

12. MYSQL 콘솔에 접속해보자! | https://itadventure.tistory.com/178

13. MySql에 넣었다가 꺼냈다가, 뭘? | https://itadventure.tistory.com/265

14. 검색진열대 MYSQL | https://itadventure.tistory.com/267

15. 편집의 왕자 MySQL | https://itadventure.tistory.com/269

16. 코드이그나이터4, MYSQL과 손잡다. | https://itadventure.tistory.com/271

17. MySQL -> 컨트롤러 -> 뷰 트리플 패스! | https://itadventure.tistory.com/272

18. 코드이그나이터! MySQL 에 입력하다! ( insert ) | https://itadventure.tistory.com/273

19. 해킹을 막아라! MySQL인젝션 보안 | https://itadventure.tistory.com/274

20. MySQL과 친해지는 phpmyadmin | https://itadventure.tistory.com/277

21. 코드이그나이터4에서 책 정보를 편집해볼까요? | https://itadventure.tistory.com/280

22. 코드이그나이터4에서 책을 지워봅시다. DELETE! | https://itadventure.tistory.com/282

23. 코드이그나이터4, 페이징 기술 | https://itadventure.tistory.com/285

24. 코드이그나이터4. 검색! | https://itadventure.tistory.com/295

25. 코드이그나이터4. 검색어 자동 추천! | https://itadventure.tistory.com/303

26. 코드이그나이터4. 네이버 검색 따라잡기-1. 대용량 자료 쾌속 검색!(1) | https://itadventure.tistory.com/304

27. 코드이그나이터4. 네이버 검색 따라잡기-2. 대용량 자료 쾌속 검색!(2) | https://itadventure.tistory.com/306

28. 코드이그나이터4. 네이버 검색 따라잡기-3. 대용량 자료 쾌속 검색!(3) | itadventure.tistory.com/310

29. 코드이그나이터4. 코드이그나이터답게 모델화! M!(Model) | itadventure.tistory.com/363

30. 코드이그나이터4. 네이버검색 따라잡기-4. 한글풀어쓰기 검색 | itadventure.tistory.com/366

31. 코드이그나이터4. 네이버검색 따라잡기-5. 영타 한글변환 검색


키보드 자판을 자세히 살펴보면 한/영키가 있습니다.
보통 영어를 타이핑할 때는 한/영 키를 누르면 영어를 입력할 수 있고
다시 한글을 타이핑할 때는 한/영 키를 한번 더 눌러 한글을 입력할 수 있지요.

인터넷 서핑을 하다 보면, 영어타이핑 모드인줄 모르고,
실수로 영어로 주르륵 타이핑했다가 다시 백스페이스를 눌러 다 지우고
한글을 입력하는 기억이 대부분 있으실 줄로 압니다.

하지만 우리 대한민국의 멋진 네이버는 이러한 경우에도 사용자들을 편하게 해주는 보정 기능이 있습니다.
( 네이버를 주로 예로 드는건 크레이가 좀 네이버파라고 그렇습니다 :) 양해해 주세요 ㅎㅎ )

영어를 타이핑한 것을 한글로 타이핑한 것처럼 인식해서 검색어 목록을 짜잔 하고 내놓는 것이지요.
원래 인터넷 익스플로러나 크롬에 있는 기능이 아니냐구요? 아뇨 이건 별도로 네이버에서 만든 기능입니다.

개발자는 좀 더 공을 들여야 하지만 사용자는 덕분에 편리합니다.
아무래도 사이트 편의성이 제공되면 사용자는 편리함 때문에 더 많이 찾게 되겠지요.
다음이나 구글과 같은 대형 사이트는 이런 기능이 지원됩니다.
하지만 개인 사이트, 개인 쇼핑몰과 같은 곳에서는 이런 기능이 드뭅니다.
자동으로 지원하는 기능이 아니기 때문이지요.

오늘은 이걸 만들어 볼겁니다.


역시 바뀐 소스 전체, 변경된 부분과 일부 설명으로 이어가도록 할텐데요.

크레이한글 클래스가 좀 수정되었습니다.
코드이그나이터4의 경우 문법 규칙이 좀 엄격해서
오류에 대해 단호하게 Warning 을 내보내지 않고 실행이 아예 멈춰버립니다.

그래서 코드이그나이터용 한글 클래스가 수정되었습니다.
아울러 영타를 한글자소로 변환할 수 있는 기능이 추가되었지요.

app\Models\CrayHangulModel.php

<?php namespace App\Models;

// 제목 : 크레이한글 클래스 ( UTF-8 )
// 설명 : 한글 자소 분리, 한글 조합을 자유롭게 수행합니다.
// 제작자 : 크레이 ( 이용운 )
// 첫오픈 : 2020. 10. 10
// 블로그 : 크레이의 IT 탐구 / https://itadventure.tistory.com
// 주석만 삭제하지 않으면 자유롭게 사용하셔도 좋습니다.
class CrayHangulModel {
	private $cho_start=0xac00; // 초성이 시작되는 코드
	private $cho_length=588; //  초성간 간격
	private $jung_length=28; //  중성간 간격

	// 초성 19글자
	private $cho_char=array(
		"ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ",
		"ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ",
		"ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ",
		"ㅋ", "ㅌ", "ㅍ", "ㅎ");

	// 중성 21글자
	private $jung_char=array(
		"ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ",
		"ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ",
		"ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ",
		"ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ",
		"ㅣ"
	);

	// 중성 27글자 + 공백1개 ( 받침이 없는 경우 )
	private $jong_char=array(
		"", "ㄱ", "ㄲ", "ㄳ", "ㄴ",
		"ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ",
		"ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ",
		"ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ",
		"ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ",
		"ㅌ", "ㅍ", "ㅎ"
	);

	// 중성 - 겹자음 자소글자를 두 글자로 나눈 것
	private $jong_char2=array(
		"", "ㄱ", "ㄲ", "ㄱㅅ", "ㄴ",
		"ㄴㅈ", "ㄴㅎ", "ㄷ", "ㄹ", "ㄹㄱ",
		"ㄹㅁ", "ㄹㅂ", "ㄹㅅ", "ㄹㅌ", "ㄹㅍ",
		"ㄹㅎ", "ㅁ", "ㅂ", "ㅂㅅ", "ㅅ",
		"ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ",
		"ㅌ", "ㅍ", "ㅎ"
	);

	private $eng2han_keys=array(
		"q"=>"ㅂ", "w"=>"ㅈ", "e"=>"ㄷ", "r"=>"ㄱ", "t"=>"ㅅ", 
		"y"=>"ㅛ", "u"=>"ㅕ", "i"=>"ㅑ", "o"=>"ㅐ", "p"=>"ㅔ",
		"a"=>"ㅁ", "s"=>"ㄴ", "d"=>"ㅇ", "f"=>"ㄹ", "g"=>"ㅎ", 
		"h"=>"ㅗ", "j"=>"ㅓ", "k"=>"ㅏ", "l"=>"ㅣ", "z"=>"ㅋ", 
		"x"=>"ㅌ", "c"=>"ㅊ", "v"=>"ㅍ", "b"=>"ㅠ", "n"=>"ㅜ", 
		"m"=>"ㅡ", "Q"=>'ㅃ', "W"=>'ㅉ', "E"=>"ㄸ", "R"=>"ㄲ",
		"T"=>"ㅆ", "Y"=>"ㅛ", "U"=>"ㅕ", "I"=>"ㅑ", "O"=>"ㅒ",
		"P"=>"ㅖ", "A"=>"ㅁ", "S"=>"ㄴ", "D"=>"ㅇ", "F"=>"ㄹ", 
		"G"=>"ㅎ", "H"=>"ㅗ", "J"=>"ㅓ", "K"=>"ㅏ", "L"=>"ㅣ", 
		"Z"=>"ㅋ", "X"=>"ㅌ", "C"=>"ㅊ", "V"=>"ㅍ", "B"=>"ㅠ", 
		"N"=>"ㅜ", "M"=>"ㅡ"
	);
	

	// 한글 한글자를 3개의 초중종성 글자 배열로 분할해줍니다. ( 3바이트 UTF8 기준 )
	// 입력)
	//   $char : UTF8 한글 한글자
	//   $jong_split : 종성이 2개의 자소인 경우 분리할지 여부, ㄳ => ㄱ, ㅅ ( 기본 = false )
	// 리턴)
	//   한글자소를 배열로 리턴합니다.
	public function split_han($char, $jong_split=false)
	{
		// 1바이트 코드인 경우
		if(strlen($char)<=1)return array($char);

		// UTF8 코드표 주소 추출
		$c1=substr($char, 0, 1);
		$c2=substr($char, 1, 1);
		$c3=substr($char, 2, 1);
		$p=ord($c1) * 65536 + ord($c2) * 256 + ord($c3); 

		// 한글이 아닌 경우
		if($p<0xeab080 || $p>0xed9ea3 )return array($char);
		
		// 1110XXXX 10XXXXXX 10XXXXXX
		// UNICODE 코드 추출
		$unicode = 
			(( ord($c1) & 15 ) << 12) +
			(( ord($c2) & 0x3f ) << 6) +
			(( ord($c3) & 0x3f ));

		// 한글 인덱스
		$hanindex = $unicode - $this->cho_start;

		// 초성 추출
		$cho=floor($hanindex / $this->cho_length);
		$hanindex-=$cho * $this->cho_length;
		$jung=floor($hanindex / $this->jung_length);
		$hanindex-=$jung * $this->jung_length;
		$jong=$hanindex;

		if($jong_split==false)
			$jongarr = $this->jong_char[$jong];
		else 
			$jongarr = $this->jong_char2[$jong];

		// echo $unicode." ( $cho / $jung / $jong ) <br/>";

		if(strlen($jongarr)==6)
			$jong_array=array(
				substr($jongarr,0,3),
				substr($jongarr,3,3)
			);
		else if(strlen($jongarr)==3)
			$jong_array=array($jongarr);
		else
			$jong_array=array();

		return array_merge(
			array(
				$this->cho_char[$cho],
				$this->jung_char[$jung]
			),
			$jong_array
		);
	}

	// 한글 조합, 한글 자소 배열을 입력, 합체된 한글 한글자를 얻습니다.
	// 입력)
	//   $chars : 한글 자소 배열. 예) array("ㄱ", "ㅏ", "ㄹ");
	// 리턴)
	//   합쳐진 한글 한글자를 리턴합니다.
	public function join_han($chars)
	{
		if(count($chars)<=1)return implode("", $chars);
		// 초성이 없으면 그냥 원본 리턴
		$cho=array_search($chars[0], $this->cho_char);
		if($cho===false)return implode("", $chars);

		// 중성이 없으면 그냥 원본 리턴
		$jung=@array_search($chars[1], $this->jung_char);
		$jung2=@array_search($chars[2], $this->jung_char);

		$jong_start=2;

		// 겹모음 예외 처리
		if(@$chars[1]=="ㅗ" && @$chars[2]=="ㅏ"){ 
			$jung=array_search("ㅘ", $this->jung_char); 
			$jong_start++; 
		}
		else if(@$chars[1]=="ㅗ" && @$chars[2]=="ㅐ"){ 
			$jung=array_search("ㅙ", $this->jung_char); 
			$jong_start++; 
		}
		else if(@$chars[1]=="ㅗ" && @$chars[2]=="ㅣ"){ 
			$jung=array_search("ㅚ", $this->jung_char); 
			$jong_start++; 
		}
		else if(@$chars[1]=="ㅜ" && @$chars[2]=="ㅓ"){ 
			$jung=array_search("ㅝ", $this->jung_char); 
			$jong_start++; 
		}
		else if(@$chars[1]=="ㅜ" && @$chars[2]=="ㅔ"){ 
			$jung=array_search("ㅞ", $this->jung_char); 
			$jong_start++; 
		}
		else if(@$chars[1]=="ㅡ" && @$chars[2]=="ㅣ"){ 
			$jung=array_search("ㅢ", $this->jung_char); 
			$jong_start++; 
		}


		if($jung===false)return implode("", $chars);
		// 종성은 합쳐서 조사
		$jongstr="";		
		for($i=$jong_start;$i<count($chars);++$i)
			$jongstr.=$chars[$i];
		$jong=array_search($jongstr, $this->jong_char);
		// 종성글자가 나눠졌을 수 있으니 한번 더 조사
		if($jong===false)$jong=array_search($jongstr, $this->jong_char2);

		$addret="";
		// 종성이 있는데도 못 찾은 경우
		if(strlen($jongstr)>0 && $jong===false)
		{
			// 종성 한글자만 찾아서 넣는다.
			$jong=array_search($chars[$jong_start], $this->jong_char);
			$addret="";
			for($i=$jong_start+1;$i<count($chars);++$i)
				$addret.=$chars[$i];
		}

		$unicode=$this->cho_start + $cho*$this->cho_length + $jung*$this->jung_length + $jong;
		// $unicode=chr($unicode >> 8).chr($unicode & 0xff);
		// XXXX XXXX XX XXXXXX
		// 1110XXXX 10XXXX XX 10XXXXXX
		$utf8code= 
			( ( ($unicode & 0xf000) << 4 ) | 0xe00000 ) +
			( ( ($unicode & 0x0fc0) << 2 ) | 0x008000 ) + 
			( ( ($unicode & 0x003f) ) | 0x00080 );
		$utf8=chr($utf8code>>16).chr(($utf8code>>8)&0xff).chr($utf8code&0xff);		
		return $utf8.$addret;
	}

	// 한글 풀어쓰기 - UTF8 전용
	// 입력)
	//   $str : 문장 - 한영 혼용 가능
	//   $jong_split : 종성이 2개의 자소인 경우 분리할지 여부, ㄳ => ㄱ, ㅅ ( 기본 = false )
	// 리턴)
	//   풀어쓰기한 자소한글 문장을 리턴합니다.
	public function hangulPuli($str, $jong_split=false)
	{
		$result="";
		for($col=0;$col<strlen($str);++$col)
		{
			$c=substr($str,$col,1);
			if((ord($c)&0x80)==0) // 일반 글자
				$result.=$c;
			else {
				$c.=substr($str, $col+1, 2);
				$col+=2;
				$result.=implode("", $this->split_han($c, $jong_split));
			}
		}
		return $result;
	}

	// 한글 조합 - UTF8 전용
	// 입력)
	//   $str : 문장 - 한글 자소로 구성된 문장
	// 리턴)
	//   모아쓰기한 자소한글 문장을 리턴합니다.
	public function hangulJohap($str)
	{
		$str=$this->hangulPuli($str, true);

		// 자소 단위로 배열에 넣는다
		$chars=array();
		$cut=array();
		for($col=0,$cnt=0;$col<strlen($str);++$col)
		{
			$c=substr($str,$col,1);			
			if((ord($c)&0x80)==0){ // 일반 글자
				$chars[$cnt]=$c;
				$cut[$cnt]=true;
				$cnt++;
			}
			else {
				$c.=substr($str, $col+1, 2);
				$col+=2;
				$chars[$cnt]=$c;
				if(in_array($c, $this->jung_char)) { // 모음인 경우
					// 바로 앞글자가 자음인 경우만
					if(in_array($chars[$cnt-1], $this->cho_char)) { 
						$cut[$cnt-1]=true; // 해당 부분 커트 정의
						$cut[$cnt]=false;
					}
					else {
						$cut[$cnt]=false;
					}
				}
				else {
					$cut[$cnt]=false;
				}
				$cnt++;
			}
		}

		// cut 단위로 문장 재구성
		$result="";
		$cc=array();	
		for($i=0;$i<count($chars);++$i)
		{
			if($cut[$i]==true){
				$result.=$this->join_han($cc);
				$cc=array($chars[$i]);
			}
			else {
				$cc[]=$chars[$i];
			}
		}
		$result.=$this->join_han($cc);
		return $result;
	}

	// 뒤에서 자소 1글자를 삭제
	// 입력)
	//   $str : 문장
	// 리턴)
	//   자소 1개를 삭제한 문장을 리턴
	public function str_backspace($str){
		$str=$this->hangulPuli($str, true);

		// 자소 단위로 배열에 넣는다
		$chars=array();
		for($col=0,$cnt=0;$col<strlen($str);++$col)
		{
			$c=substr($str,$col,1);
			if((ord($c)&0x80)==0){ // 일반 글자
				$chars[$cnt]=$c;
				$cnt++;
			}
			else {
				$c.=substr($str, $col+1, 2);
				$col+=2;
				$chars[$cnt]=$c;
				$cnt++;
			}
		}

		// 마지막 글자를 제외하고 모두 합침
		$result="";
		for($i=0;$i<count($chars)-1;++$i)
		{
			$result.=$chars[$i];
		}
		return $this->hangulJohap($result);
	}

	// 영타 문장을 한타를 친 것처럼 변환
	// 입력)
	//   $str : 영타문장
	// 리턴)
	//   한글로 변환 가능하면 변환한 자소목록, 실패시 공백 리턴
	function eng2han($engstr)
	{
		$result="";
		for($i=0;$i<strlen($engstr);++$i)
		{
			$c=substr($engstr, $i, 1);
			if(array_key_exists($c, $this->eng2han_keys))
				$result.=$this->eng2han_keys[$c];
			else return "";	// 한글타자 변환 실패
			
		}		
		return $result;
	}

};

?>

app\Models\BookModel.php

북모델 클래스에 Ajax 검색 기능을 지난번에 넣었지요?
이 부분이 변경되었습니다. 영타를 한타로 바꿔서 한번 검색해주는 것이 바로 그것이지요.

<?php namespace App\Models;

use CodeIgniter\Model;
use App\Models\CrayHangulModel;

class BookModel extends Model
{
    public $db;

    // 클래스 생성자
    public function __construct()
    {
        $this->db = \Config\Database::connect("default", false);
    }

    public function get_query()    
    {        
        $sql = "select * FROM book";
        return $this->db->query($sql);
    }

    // 단어 사전 만들기
    public function MakeBookWord()
    {
        // 크레이한글 모델 클래스
        $CrayHangul = new CrayHangulModel();
        ini_set('memory_limit', -1);
        $query_cnt = $this->db->query("SELECT count(*) as cnt FROM book");
        $total = $query_cnt->getResultArray()[0]['cnt'];        
        $limit=1000; // 1000 건씩 끊어서 처리
        $word_arr=array();

        $special_chars=array(
            "[", "]", "(", ")", ",", ":", ";", "<", ">",
            "&", "?"
        );
        // 유지할 단어 + - * / . %
        for($step=0;$step<$total;$step+=$limit)
        {
            $results = $this->db->query(
                "SELECT number, title FROM book 
                order by number 
                limit $step, $limit"
            )->getResultArray();
            foreach($results as $result)
            {
                foreach($special_chars as $char){
                    $result['title']=str_replace($char, " ", $result['title']);
                }
                $explode = array_unique(explode(" ", trim($result['title'])));
                foreach($explode as $word)
                {
                    if(strlen($word)<=1)continue;                    
                    if(!empty($word_arr[$word]))$word_arr[$word].=",";
                    $word_arr[$word].=$result['number'];
                }                    
            }
        }

        echo count($word_arr)."개<br/>";
        ob_flush(); flush();

        $cnt=0;
        $this->db->query("drop table book_search");
        $this->db->query("create table book_search (
            word varchar(120),
            numbers text
        )");
        $i=0;
        $this->db->transStart();
        foreach($word_arr as $word=>$numbers){
            $i++;
            $word_puli = $CrayHangul->hangulPuli($word);
            echo "$i: $word => $word_puli / ".$numbers."<br/>";
            $sql="insert into book_search (word, numbers)
            values ('".addslashes($word_puli)."', '".addslashes($numbers)."')";
            $this->db->query($sql);
            $cnt++;
            if($cnt>=100)
            {
                $this->db->transComplete();
                $this->db->transStart();
                $cnt=0;
            }
        }
        $this->db->transComplete();
        $this->db->query("ALTER TABLE book_search ADD INDEX(word);");
        
        echo "단어사전 입력이 완료되었습니다.";
    }

    // 책 삽입    
    public function BookInsert($data)
    {
        $set=array();
        foreach($data as $fld=>$value)
            $set[]="$fld='".
            $this->db->escapeString($value).
            "'";
        $this->db->query(
            "insert into book set ".
            implode(", ", $set)
        );
    }

    // 책 수정
    public function BookEdit($number, $data)
    {
        $set=array();
        foreach($data as $fld=>$value)
            $set[]="$fld='".
            $this->db->escapeString($value).
            "'";
        $this->db->query("update book set ".
            implode(", ", $set).
            "where number=".$number." limit 1"
        );
    }

    // 책 삭제
    public function BookDelete($number)
    {
        $this->db->query("delete from book
            where number=".$number." limit 1"
        );
    }

    // 검색조건에 따른 갯수, where 쿼리문 추출
    public function BookSearchCount($searchword)
    {
        // 크레이한글 모델 클래스
        $CrayHangul = new CrayHangulModel();
        $searchword=$CrayHangul->hangulPuli($searchword);
        $where_sql="";
        if($searchword!=""){
            $query_search=$this->db->query(
                $sql="SELECT numbers FROM book_search 
                where word like '".addslashes($searchword)."%'");
            $results_search = $query_search->getResultArray();
            $numbers = array();
            foreach($results_search as $one)
            {
                $tmp=explode(",", $one['numbers']);
                $numbers = array_merge($numbers, $tmp);
            }
            $total=count($numbers);
            sort($numbers);
            $numbers=implode(",", $numbers);
            if($numbers!="")
                $where_sql="where number in ($numbers)";
            else $where_sql="where 0";
        }
        else 
        {
            $query_count = $this->db->query(
                "SELECT count(*) FROM book $where_sql");
            $results_count = $query_count->getResultArray();
            $total = $results_count[0]['count(*)'];    
        }
        return array($where_sql, $total);
    }

    // ajax 쿼리
    function BookSearchAjax($searchword)
    {
        // 크레이한글 모델 클래스
        $CrayHangul = new CrayHangulModel();
        $searchword=$CrayHangul->hangulPuli($searchword);
        $query = $this->db->query(
            "SELECT numbers FROM book_search 
            where word like '".addslashes($searchword)."%'");
        $results = $query->getResultArray();
        $numbers=array();
        foreach($results as $result)
            $numbers=array_merge(
                $numbers, 
                explode(",", $result['numbers']));
        sort($numbers);
        $numbers=implode(",", $numbers);
        if($numbers==""){            
            $new_searchword = $CrayHangul->eng2han($searchword);
            if($new_searchword!=$searchword && $new_searchword!=""){                
                $result = $this->BookSearchAjax($new_searchword);
                $result[1]=$CrayHangul->hangulJohap($new_searchword);
                return $result;
            }
            die();
        }
        
        $query = $this->db->query(
            "SELECT distinct title FROM book where 
            number in ($numbers) limit 10");
        $results = $query->getResultArray();
        return array($results, "");
    }

}

app\Controllers\BookAjax7.php

타이핑할 때 ajax 실행하는 컨트롤러 소스가 변경되었습니다.
영타에서 자동으로 한글로 바뀐 경우 어떠어떠한 결과로 다시 검색했다는 부분을 보여주기 위함인데요.

<?php
namespace App\Controllers;
use CodeIgniter\Controller;
use App\Models\BookModel;

class BookAjax7 extends Controller
{
    public function index()
    {
        $db = \Config\Database::connect("default", false);
        $BookModel = new BookModel();
        $searchword=trim($this->request->getVar("searchword"));
        list($results, $new_searchword)=$BookModel->BookSearchAjax($searchword);        
        if($new_searchword!="")
            $new_searchword=
                "<span style='color:green;text-decoration:underline'>'".
                $new_searchword.
                "' 키워드로 대신 검색한 결과입니다.</span><br/>";
        $data = [
            'booklist'=>$results,
            'new_searchword'=>$new_searchword
        ];
        return view('bookajax', $data);
    }
}


뷰도 함께 바뀌었습니다.
app\Views\bookajax.php

<?=$new_searchword?>
<? foreach ($booklist as $book){?>
<span onclick="search_input(this)" style="cursor:pointer"><?=$book['title']?></span><br/>
<? } ?>

 

주요 변경된 부분만 내용을 살펴보도록 할까요?

우선 한글 컨트롤러에 영타를 한글자소로 바꿔주는 메소드가 추가되었습니다.

class CrayHangulModel {

    :
    
	private $eng2han_keys=array(
		"q"=>"ㅂ", "w"=>"ㅈ", "e"=>"ㄷ", "r"=>"ㄱ", "t"=>"ㅅ", 
		"y"=>"ㅛ", "u"=>"ㅕ", "i"=>"ㅑ", "o"=>"ㅐ", "p"=>"ㅔ",
		"a"=>"ㅁ", "s"=>"ㄴ", "d"=>"ㅇ", "f"=>"ㄹ", "g"=>"ㅎ", 
		"h"=>"ㅗ", "j"=>"ㅓ", "k"=>"ㅏ", "l"=>"ㅣ", "z"=>"ㅋ", 
		"x"=>"ㅌ", "c"=>"ㅊ", "v"=>"ㅍ", "b"=>"ㅠ", "n"=>"ㅜ", 
		"m"=>"ㅡ", "Q"=>'ㅃ', "W"=>'ㅉ', "E"=>"ㄸ", "R"=>"ㄲ",
		"T"=>"ㅆ", "Y"=>"ㅛ", "U"=>"ㅕ", "I"=>"ㅑ", "O"=>"ㅒ",
		"P"=>"ㅖ", "A"=>"ㅁ", "S"=>"ㄴ", "D"=>"ㅇ", "F"=>"ㄹ", 
		"G"=>"ㅎ", "H"=>"ㅗ", "J"=>"ㅓ", "K"=>"ㅏ", "L"=>"ㅣ", 
		"Z"=>"ㅋ", "X"=>"ㅌ", "C"=>"ㅊ", "V"=>"ㅍ", "B"=>"ㅠ", 
		"N"=>"ㅜ", "M"=>"ㅡ"
	);
    
    :
    
	// 영타 문장을 한타를 친 것처럼 변환
	// 입력)
	//   $str : 영타문장
	// 리턴)
	//   한글로 변환 가능하면 변환한 자소목록, 실패시 공백 리턴
	function eng2han($engstr)
	{
		$result="";
		for($i=0;$i<strlen($engstr);++$i)
		{
			$c=substr($engstr, $i, 1);
			if(array_key_exists($c, $this->eng2han_keys))
				$result.=$this->eng2han_keys[$c];
			else return "";	// 한글타자 변환 실패
			
		}		
		return $result;
	}
};

추가된 멤버변수 $eng2han_keys 는 영타에 해당하는 한글 자소 배열인데요.
기본을 소문자, Shift 키와 함께 누르면 대문자로 취급해서
소문자는 기본자음과 기본모음에 대응하도록 하고
대문자는 겹자음과 겹모음에 대응하도록 사전에 선언한 것입니다.

그리고 eng2han 메소드에서 입력된 글자를 하나하나 비교해서 한글자소로 바뀌줍니다.
"dndb"를 검색하면 "ㅇㅜㅇㅠ"로 바꿔서 그 결과를 반환해 주는 것이지요.

하지만 중간에 한 글자라도 매칭되는 글자가 없으면 실패로 간주해서 공백문자열을 반환합니다.
변환에 실패했다는 의미이지요.

이 함수는 BookModel 모델의 Ajax  검색하는 메소드에서 사용하는데요.
아래 부분이 변경되었습니다.
원래는 검색결과가 없으면 바로 종료하던 부분이었으나 한번 더 검색을 수행합니다.
영타를 한타로 바꾸어서 한글 변경에 성공한 경우 한글로 한번 더 검색하고, 그 결과를 반환합니다,

    :
if($numbers==""){            
    $new_searchword = $CrayHangul->eng2han($searchword);
    if($new_searchword!=$searchword && $new_searchword!=""){                
        $result = $this->BookSearchAjax($new_searchword);
        $result[1]=$CrayHangul->hangulJohap($new_searchword);
        return $result;
    }
    die();
}
    :

Ajax 를 검색하는 컨트롤러 소스에서는 그 결과를 받아서,
만일 변환이 검색된 적이 있다면 $new_searchword 변수에 어떻게 변환되었는지
변환결과를 알려주는 HTML 태그를 구성합니다. 그리고  View 에 넘겨주는 것이지요.

    :
list($results, $new_searchword)=$BookModel->BookSearchAjax($searchword);        
if($new_searchword!="")
    $new_searchword=
       "<span style='color:green;text-decoration:underline'>'".
       $new_searchword.
        "' 키워드로 대신 검색한 결과입니다.</span><br/>";
$data = [
    'booklist'=>$results,
    'new_searchword'=>$new_searchword
];
    :

뷰에서는 단 한줄이 추가되었습니다.
변환된 경우 변환된 내용을 보여주는 것이지요.

<?=$new_searchword?>
   :

아래 URL을 통해 이 소스를 실행 후, 제목 검색 창에서 영타로 한글을 입력해주시면,

http://localhost/bookList7

아래와 같이 변환된 단어와 검색결과가 함께 노출되어 선택할 수 있습니다.

오늘도 필요하신 분에게 도움이 되셨나 모르겠습니다.

코로나가 1단계로 내려가서 많은 분들이 다시금 안정적인 자리를 찾아갈 수 있는 길이 열려 다행이라 생각됩니다.
아무쪼록 모두들 건강하시며 하나님의 보호하심이 함께 하시길 소원합니다.

오늘도 여기까지 읽어주셔서 감사합니다. :)