반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


이번에는 getTextUsingTransformations() 함수를 살펴볼 차례죠?


제 생각에 오늘로 소스 분석이 모두 끝날 것 같습니다.

사실 제가 할 작업은 지금까지 분석한 것으로도 충분하거든요.

벌써 미팅에서 결과를 공유했고 그 다음 단계가 진행중입니다.


하지만 시작했으니 마저 끝마쳐보죠.


pdf2text() 함수의 맨 마지막 return 문에 있는 코드 입니다.


return getTextUsingTransformations($texts, $transformations);


파라미터로는 getDirtyTexts() 함수에서 얻었던 $texts 가 첫번째에 있네요.

이 내용은 지난 글 말미에 보여드렸습니다.


두번째 파라미터는 getDecodedStream() 함수를 통해서 얻었던 $data 입니다.


getTextUsingTransformations($texts, $transformations) 함수를 볼까요?


function getTextUsingTransformations($texts, $transformations) {
    $document = "";
    for ($i = 0; $i < count($texts); $i++) {
        $isHex = false;
        $isPlain = false;

        $hex = "";
        $plain = "";
        for ($j = 0; $j < strlen($texts[$i]); $j++) {
            $c = $texts[$i][$j];
            switch($c) {
                case "<":
                    $hex = "";
                    $isHex = true;
                break;
                case ">":
                    $hexs = str_split($hex, 4);
                    for ($k = 0; $k < count($hexs); $k++) {
                        $chex = str_pad($hexs[$k], 4, "0");
                        if (isset($transformations[$chex]))
                            $chex = $transformations[$chex];
                        $document .= html_entity_decode("&#x".$chex.";");
                    }
                    $isHex = false;
                break;
                case "(":
                    $plain = "";
                    $isPlain = true;
                break;
                case ")":
                    $document .= $plain;
                    $isPlain = false;
                break;
                case "\\":
                    $c2 = $texts[$i][$j + 1];
                    if (in_array($c2, array("\\", "(", ")"))) $plain .= $c2;
                    elseif ($c2 == "n") $plain .= '\n';
                    elseif ($c2 == "r") $plain .= '\r';
                    elseif ($c2 == "t") $plain .= '\t';
                    elseif ($c2 == "b") $plain .= '\b';
                    elseif ($c2 == "f") $plain .= '\f';
                    elseif ($c2 >= '0' && $c2 <= '9') {
                        $oct = preg_replace("#[^0-9]#", "", substr($texts[$i], $j + 1, 3));
                        $j += strlen($oct) - 1;
                        $plain .= html_entity_decode("&#".octdec($oct).";");
                    }
                    $j++;
                break;

                default:
                    if ($isHex)
                        $hex .= $c;
                    if ($isPlain)
                        $plain .= $c;
                break;
            }
        }
        $document .= "\n";
    }

    return $document;
}


먼저 $document 변수를 만들어 놓네요. 맨 밑에 보니까 return 될 값이 들어갈 변수입니다.

즉 사람이 읽을 수 있는 완전한 데이터가 들어갈 변수죠.


다음은 $texts 의 count 만큼 for 문을 돌립니다.

그 for문 안에서 맨 먼저 하는 일은 4개의 변수를 정의해 놓는 거네요.

$isHex와 $isPlain 는 boolean 값이 들어갈 변수고 $hex와 $plain 은 어떤 문자 같은게 들어갈 변수인것 같습니다.


여기서 다시 for 문을 돌립니다. $texts 가 이중배열이라서 이렇게 작업하나 봅니다.

두번째 for 문에서는 $c 변수에 $texts[$i][$j] 를 담습니다.


그 다음에 switch 문이 나오는데... 처음에 < 와 > 를 체크하는 군요.


편의를 위해서 어제 봤던 데이터 중 일부를 아래 복사해 넣겠습니다.


(W)-36(e)7(e)7(k )46(o)7(f)
( )
(Oct)-11(o)5(ber )10(1)4( )
<00B2>
( )
(Oct)-11(o)5(ber )10(5)
( )
( )
( )
(Who)5(l)7(e)7( )-19(+ )-2(S)3(um)5( )
( )
( )
(Choice)
( )
(+)
( )
(F)20(lavor)


<00B2> 가 있네요. < 인 경우에는 $isHex 가 true 이고 > 인 경우에는 false 입니다.

그리고 > 인 경우에는 $hex 값을 array 로 바꿉니다.

str_split() 함수에서 그 일을 하죠.


<?php

$str 
"Hello Friend";

$arr1 str_split($str);
$arr2 str_split($str3);

print_r($arr1);
print_r($arr2);

?>


위 소스를 돌리면 아래 값을 얻습니다.

Array
(
    [0] => H
    [1] => e
    [2] => l
    [3] => l
    [4] => o
    [5] =>
    [6] => F
    [7] => r
    [8] => i
    [9] => e
    [10] => n
    [11] => d
)

Array
(
    [0] => Hel
    [1] => lo
    [2] => Fri
    [3] => end
)


어떤 일을 하는 함수인지 아시겠죠?

그 다음에는 $hexs 의 count 만큼  for 문을 돌립니다.

그 다음 그 각각의 값을 지난번에도 나왔던 str_pad() 함수를 사용해서 0을 4칸 붙이네요.


그 다음에 if 문에서 $transformations[$chex] 이 세팅돼 있으면 $chex 변수에 $transformations[$chex]을 대입합니다. 


그리고 나서 $document 에 값을 집어 넣는데요.

html_entity_decode() 함수를 사용합니다.


이 것은 html 을 string 으로 바꿔 주는 함수입니다.


<?php
$orig 
"I'll \"walk\" the <b>dog</b> now";

$a htmlentities($orig);

$b html_entity_decode($a);

echo 
$a// I'll &quot;walk&quot; the &lt;b&gt;dog&lt;/b&gt; now

echo $b// I'll "walk" the <b>dog</b> now
?>


위 예제를 보시면 어떤 일을 하는지 아시겠죠?


그러니까 <> 감싸여진 데이터는 hex 코드라서 이 case 문에서 그것을 처리하는 거네요.


그 다음 case 문에서는 (,) 를 체크합니다.


() 로 둘러싸인 부분은 그냥 text 죠. 사람이 읽을 수 있는..

그러니까 별다른 처리를 하지 않아도 되기 때문에 ) 인 경우에 $document 에 $plain 을 그냥 추가해 버리는 겁니다.


다음에는 \\ 를 체크하는데요.


우리가 다루는 pdf 파일에서는 이 값이 추출 되지 않았습니다.

어쨌든 내용을 보면 줄바꿈, 탭 뭐 이런 것들을 해당 sign 으로 바꿔서 $plain 에 넣는 일을 하네요. 숫자인 경우에는 거기에 맞게 또 처리를 하구요.


디폴트로는 $isHex 일 경우 $hex 에 $c를 추가하고 $isPlain 일 경우 $plain 에 $c를 추가합니다.


그리고 이렇게 만든 $document 를 이전 for 문에서 만든 $document 에 가를 하구요.

이렇게 for 문이 다 돌고 $document 에 값이 다 쌓였으면 이 값을 return 합니다.


그 return 값이 사람이 볼 수 있는 text 입니다.


이렇게 해서 얻은 결과는 아래와 같습니다.



잘 안 보이실 텐데요. 1번 글에서 업로드한 파일들을 다운 받아서 돌려 보시면 됩니다.


참고로 이 데이터를 가지고 요일별 메뉴를 display 하는 함수를 제가 만들어 봤는데요.



function menus($sources){
$resultlen  = strlen($sources);

$menuDate = substr($sources,0,48);
echo "<b><font size=6>Start Menu</font> <p><br> ". $menuDate. "<p></b>";


$result = preg_replace("/\s+/",'_',$sources);

$fs1 = strrpos($result,'_M_');

$menu1 = substr($result,$fs1,$resultlen);

$startTue = strpos($menu1,'_T_');
$startWed = strpos($menu1,'_W_');
$startThu = strrpos($menu1,'_T_');
$startFri = strpos($menu1,'_F_');
$endFri = strpos($menu1,'WEEKLY');

$Monday = str_replace('_', ' ' ,str_replace('_M_','Monday <br>',str_replace('FIT','FIT<br>',substr($menu1,0,$startTue))));
$Tuesday = str_replace('_', ' ' ,str_replace('_T_','Tuesday <br>',str_replace('FIT','FIT<br>',substr($menu1,$startTue,$startWed-$startTue))));
$Wednsday = str_replace('_', ' ' ,str_replace('_W_','Wednsday <br>',str_replace('FIT','FIT<br>',substr($menu1,$startWed,$startThu-$startWed))));
$Thuesday = str_replace('_', ' ' ,str_replace('_T_','Thusday <br>',str_replace('FIT','FIT<br>',substr($menu1,$startThu,$startFri-$startThu))));
$Friday = str_replace('_', ' ' ,str_replace('_F_','Friday <br>',str_replace('FIT','FIT<br>',substr($menu1,$startFri))));

echo "<table width=50%><tr><td>";

echo "<p> ". $Monday . "<p>";
echo "<p> ". $Tuesday . "<p>";
echo "<p> ". $Wednsday . "<p>";
echo "<p> ". $Thuesday . "<p>";
echo "<p> ". $Friday . "<p>";

echo "</td></tr></table><p><br><p> ";
}


그리고 함수 밖에서 이걸 부르면 되죠.

menus($result);

이렇게 하면 아래와 같은 결과가 나옵니다.




이렇게 해서 PDF 를 TEXT 로 변환하는 PHP 프로그램을 모두 분석해 봤습니다.

오랫만에 목욕해서 때를 싹 밀었을 때 처럼 개운하네요.


분석결과 위 소스는 제가 일하는데에서는 맞지 않아서 사용하지 않기로 했거든요.

그래서 저 결과도 깔끔하게 나온 것은 아닙니다.

참고하시구요.


다음에 또 소스 분석할 일 있으면 블로그에 정리해 놓을 께요.

이번 글은 기분 좋게 7번째 만에 마무리 했네요.





반응형

Comment