이미지로 된 수식을 아래 한/글에 입력하는 스크립트

수학문제를 이미지 파일로 가지고 있을 때, 일전에 이야기한 mathpix[1]으로 수식을 LaTeX으로 변환할 수 있다. 이 변환결과를 입력하여 아래 한/글에서 수식으로 변환하여 입력하는 스크립트다.

동일한 스크립트를 여러 다른상황에서 쓸 수 있도록 만들었음. 본인은 한/글 2010을 쓰고 있어서, 다른 버전에서 작동을 보증하지 않음.

function OnScriptMacro_mathpix_ocr()
{
	var text = determine_eq_ob_nothing();

	if ( text == 'nothing')		//커서가 텍스트 입력상태일 때
	{
		text = GetTextFile("UNICODE","saveblock");

		if( text )		//텍스트가 블럭선택되어 있는 상태일 때
		{

			//이 부분에 넣고 싶은 기능을 넣으면 됨. ㅋㅋㅋㅋ

		}
		else		//텍스트 블럭이 아닌 상태 mathpix
		{
			var script = new ActiveXObject('MSScriptControl.ScriptControl');
			script.language = 'vbscript';
			var text = script.eval('inputbox("mathpix","입력")');

			//frac 처리
			var frac1 = text.search(/\\frac/), frac2, stop_inf=0;

			while( frac1> -1 && stop_inf < 40)
			{
				frac2 = braces_match(text, frac1);

				if(frac2 > -1)
				{
					text = text.substring(0,frac1) + text.substring(frac1,frac2).replace(/^\\frac/,'') + 'over' + text.substring(frac2);
					frac1 = text.search(/\\frac/)
				}
				stop_inf++;
			}

			//case 처리
			if ( text.search(/\\left\\\{\\begin\{array\}/) > -1)
			{
				text=text.replace(/\\left\\\{\\begin\{array\}\{[^\}]*\}/,'cases{');
				text=text.replace(/\\end\{array\}\\right\./,'}');
				text=text.replace(/\\\\/g,'#');
			}
			if( /\\left\\\{\\begin\{aligned\}/.test(text) )
			{
				text=text.replace(/\\left\\\{\\begin\{aligned\}/,'cases{');
				text=text.replace(/\\end\{aligned\}\\right\./,'}');
				text=text.replace(/\\\\/g,'#');
			}


			//align처리
			if( /^\\begin\{aligned\}/.test(text) )
			{
				text=text.replace(/^\\begin\{aligned\}/,'');
				text=text.replace(/\\end\{aligned\}$/,'');
				text=text.replace(/\\\\\s*([^&=\+\-\s])/g,', $1');		//식이 이어지고 있다고 추정되는 문자에는 콤마 뺌
				text=text.replace(/(\\\\)?\s*\&/g,'');
			}
			if ( text.search(/^\s*\\begin\{array\}/) > -1)		//식들의 병렬 배치
			{
				text=text.replace(/\\begin\{array\}\{[^\}]*\}\{/,'');
				text=text.replace(/\}\\end\{array\}/,'');

					//뒤에 quad를 기준으로 끊는 부분 있음		식이 끊어지는지 이어지는지 판정
				text=text.replace(/\}\s*\\\\\s*\{\s*\\quad\s*([\+=<>])/g,' $1');
				text=text.replace(/\}\s*\\\\\s*\{\s*\\quad\s*([^\+=<>\s])/g,' quad $1');		//마이너스는 식이 끊어지는 경우 있으므로 불포함

				text=text.replace(/\}\s*\\\\\s*\{\s*([\+=<>])/g,' $1');
				text=text.replace(/\}\s*\\\\\s*\{\s*([^\+=<>\s])/g,' quad $1');		//마이너스는 식이 끊어지는 경우 있으므로 불포함

			}

			//tex 기호를 한글 기호로 
			text=text.replace(/_\{([^\{\}]+)\}\s*\\mathbf\{C\}_\{([^\{\}]+)\}/g,'_{$1}{rm C}_{$2}');			//콤비네이션 처리
			text=text.replace(/\\boldsymbol\{([^\}]+)\}/g,'$1');		//볼드체 제거
			text=text.replace(/\\mathbf\{([^\}]+)\}/g,'$1');		//볼드체 제거
			text=text.replace(/\\geqq?/g,' ge ');
			text=text.replace(/\\leqq?/g,' le ');
			text=text.replace(/\\rightarrow/g,'->');
			text=text.replace(/\\pm/g,'+-');
			text=text.replace(/\\mp/g,'-+');
			text=text.replace(/\^\{((\\prime\s*)+)\}/g,'$1');
			text=text.replace(/\\overline/g,' bar');
			text=text.replace(/(left)?\\\{/g,' left{');
			text=text.replace(/(right)?\\\}/g,' right}');
			text=text.replace(/\^\{\s*\\circ\}/g,' DEG ');
			text=text.replace(/\\equiv/g,' == ');
			text=text.replace(/(^|\{)_/g,'$1`_');		//콤비네이션
			text=text.replace(/\\operatorname\{([^\}]+)\}/g,'$1');			//operatorname 제거
			text=text.replace(/<\-/g,'< -');							//좌측 화살표<-는 없다고 가정
			text=text.replace(/lim\s*_\s*\{([^\-]+)\->\s*([\+\-])([^\}]+)\}/g,'lim_{$1->$3$2}');		//lim_{x->+0}을 lim_{x->0+}로 변경
			text=text.replace(/\\,/g,'`');

			if( /\\overrightarrow/.test(text) )
			{
				text=text.replace(/\\overrightarrow/g,' vec');
				text=text.replace(/\\cdot/g,' bullet ');
			}


			//\Leftrightarrow 처리는 eqprint 함수 안에서


			//rm 처리
			text=text.replace(/\\mathrm\{/g,'{rm ');
			text=text.replace(/(vec|bar)\s*\{\s*([A-Z])\s*(_\{[0-9]\})?\s*([A-Z])\s*(_\{[0-9]\})?/g,'$1{rm $2$3$4$5');

			text=text.replace(/\{\{([^\{\}]*)\}\}/g,'{$1}');		//괄호 중복 제거
			text=text.replace('','');			//전각 공백 제거
			text=text.replace(/\\/g,' ');


			var seperated_equation = text.split('quad'), i, pos, stop_inf = 0;

			for(i = 0; i< seperated_equation.length-1 && stop_inf < 20; i++)		//만약 quad로 나누어 진다고 하더라도 중괄호가 안 맞으면 결합함
			{
				pos = braces_match(seperated_equation[i]);
				if ( /[\}\{]/.test(seperated_equation[i]) && pos == -1)
				{
					seperated_equation[i] = seperated_equation[i] + seperated_equation[i+1];
					seperated_equation.splice(i+1, 1);
				}

				stop_inf++;
			}

			for(i = 0; i< seperated_equation.length; i++)
			{
				if( /\s*,\s*`\s*$/.test(seperated_equation[i]) )
				{
					eqprint( seperated_equation[i].replace(/\s*,\s*`\s*$/, '') );
					print(', ');
				}
				else if( /^\s*\(.*\)\s{0,}$/.test(seperated_equation[i]) )
				{
					print(' (');
					eqprint( seperated_equation[i].replace(/^\s*\((.*)\)\s{0,}$/, '$1') );
					print(')');
				}
				else
				{
					eqprint( seperated_equation[i] );
				}
			}
		}
	}
	else if ( text )		//수식 개체가 선택된 경우
	{

			//이 부분에 넣고 싶은 기능을 넣으면 됨. 수식 내용을 변경한다든지 등등등.

	}
	else		//그리기 개체가 선택된 경우
	{

			//이 부분에 넣고 싶은 기능을 넣으면 됨. 그리기 개체 사이즈를 통일한다든지 등등등.
/*
		HAction.GetDefault("ShapeObjDialog", HParameterSet.HShapeObject.HSet)
		with (HParameterSet.HShapeObject)
		{


		}
		HAction.Execute("ShapeObjDialog", HParameterSet.HShapeObject.HSet);
*/
	}

}

/////////////
////서브루틴
//현재 커서에 수식이 선택되면 수식 텍스트 반환, 그리기 개체가 선택되면 ''반환, 아무것도 아니면 'nothing'반환
function determine_eq_ob_nothing()
{
	if (HAction.GetDefault("EquationPropertyDialog", HParameterSet.HShapeObject.HSet) )	//수식, 개체는 true
	{
		with (HParameterSet.HShapeObject)
		{
			text = String;
		}
		HAction.Execute("EquationPropertyDialog", HParameterSet.HShapeObject.HSet);

		//그리기 개체일 때, 이 부분에 print 함수 쓰면 한/글 비정상 종료됨

		return text;
	}
	return 'nothing';		//현재 커서에 오브젝트가 선택되지 않은 경우
}


//출력 함수
function print(text)
{
	HAction.GetDefault("InsertText", HParameterSet.HInsertText.HSet);
	HParameterSet.HInsertText.Text = text;
	HAction.Execute("InsertText", HParameterSet.HInsertText.HSet);
}


//수식 출력함수
function eqprint(text)
{
	var arr = text.split(/Leftrightarrow/), i;

	for(i=0; i<arr.length; i++)
	{
		if( i !=0 )
		{
			print( ' ⇔ ');
		}

		HAction.GetDefault("EquationCreate", HParameterSet.HEqEdit.HSet);
		with (HParameterSet.HEqEdit)
		{
			BaseUnit = PointToHwpUnit(10.0);
			String = arr[i];
		}
		HAction.Execute("EquationCreate", HParameterSet.HEqEdit.HSet);
	}
}


//문자열(text)과 시작위치(frac1)을 입력하면 이후 중괄호 짝이 맞는 최대 문자열 위치를 반환한다.	괄호가 없거나 안 맞으면 -1 반환
function braces_match(text, frac1)
{
	var counter = 1;

	var frac2 = text.indexOf('{', frac1);		//최초 스타트 상태에서 괄호의 개수가 영개이므로 처음 괄호가 시작되는 위치를 찾는다.
	if (frac2 == -1)		//에러 처리
	{
		return -1;
	}

	for(i=frac2+1; i<text.length && counter > 0; i++)
	{
		if( text.charAt(i) == '{' )
		{
			counter++;
		}
		if( text.charAt(i) == '}' )
		{
			counter--;
		}
	}

	if ( counter<0 || (i == text.length && counter != 0) )			//에러 처리
	{
		return -1;
	}
	return i;
}

inputbox 불러내서 입력하는 부분에서, 입력 글자제한이 있어서, 너무 긴 수식은 입력 안 되는 수가 있음.

.


[1] 내 백과사전 Mathpix : 수식 이미지를 LaTeX으로 자동변환하는 프로그램 2019년 4월 11일

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

This site uses Akismet to reduce spam. Learn how your comment data is processed.