문자열에서 수학기호를 논리 연산식 처럼 바꾸는 게 잘 안 되네요...

qkrskek의 이미지

안녕하세요.

수학 기호와 일반 문자열로 구성되어 있는 텍스트 파일이 있는데,

이 파일을 제가 쓰는 Tool 이 인식할 수 있도록

수학 기호를 논리 연산식 처럼 바꾸는 중 입니다.

예를 들면 ( AAA & BBB ) ---> ( AAA AND BBB ) 이런 식입니다.

간단한 것들은 sed 로 하면 되는데, 복잡한 수식이 많아서 힘드네요.

복잡한 수식은 이런 식입니다.

예 : ( AAA + BBB ) + [ { ( CCC + DDD + EEE ) - FFF } & GGG ]

최종답 : ( AAA OR BBB ) OR [ ( ( OR CCC DDD EEE ) NOT FFF ) AND GGG ]

특히, ( CCC + DDD + EEE ) ---> ( OR CCC DDD EEE ) 이 부분은 어떻게 해야 할지 모르겠네요...

그냥 ( CCC OR DDD OR EEE ) 로 하면 Tool 문법 오류로 Fail 납니다.

perl 의 split line 으로 해 볼려고 하는데, 잘 안 되네요.

고수들의 좋은 의견 부탁드립니다.

감사합니다.

익명 사용자의 이미지

피연산자가 3개 이상일 때 연산자를 앞에 둬야 하는 규칙이 있네요.

단순 치환으로는 안 되고 파서를 만들어야 하지 않을까요?

raymundo의 이미지

괄호가 중첩되는 형태의 텍스트의 경우 정규식으로 하는 것보다 Text::Balanced 같은 모듈을 쓰라는 게 권장사항입니다만, 구조가 명확한 룰을 따른다면 어떻게든 할 수는 있을 겁니다.

제일 안쪽 괄호 안의 내용을 따로 저장하고 그 자리를 하나의 항으로 치환하는 과정을 반복하고
 
   ( AAA + BBB ) + [ { ( CCC + DDD + EEE ) - FFF } & GGG ]
=>     TERM1     + [ {        TERM2        - FFF } & GGG ]
=>     TERM1     + [               TERM3           & GGG ]
=>     TERM1     +                   TERM4
=> TERM5
 
그 다음은 역으로 하나의 항을 원하는 형태의 괄호식으로 바꾸면서 치환
 
   TERM5
=> ( TERM1 OR TERM4 )
=> ...

다음과 같이 가정하고,
* 괄호는 중첩되는 경우( [A{B}C] )만 있지 꼬이는 경우( [A{B]C} )는 없음
* 괄호 안에 항이 3개 이상일 때는 사용되는 연산자는 하나 뿐임([A+B+C]만 있지 [A+B-C]는 없음) - 안 그러면 연산자들 우선순위를 생각해야 할 판이라서
* 피연산자 중에 "TERM3" 과 같이 "TERM" + 숫자 로 된 피연산자는 없음 (있다면, 코드를 고쳐서 절대로 나오지 않는 문자열을 쓰시면 됩니다)

일단 본문에 있는 식은 제대로 변환되는 걸 확인했는데, 버그가 있을지도 모르겠네요.

use strict;
use warnings;
 
my $str = '( AAA + BBB ) + [ { ( CCC + DDD + EEE ) - FFF } & GGG ]';
 
# 각 부분식을 저장할 해시와, 부분식의 인덱스
my $idx = 0;
my %save;
 
 
# 전체 식을 괄호로 한 번 감싸서 하나의 항으로 만듦
$str = "( $str )";
 
# 가장 안쪽 괄호부터 차례대로 저장
while ( 
    $str =~ s/
                ( [(\[\{] )     # 시작 괄호
                \s*             # 공백이 있을 수도
                ( [^(\[\{]+? )  # 괄호 안의 내용
                \s*
                ( [)\]\}] )     # 끝 괄호
            /
                save($1,$2,$3)  # 이 식을 변환,저장한 후 'TERM숫자' 형태로 치환
            /gex
) {}
 
# 'TERM숫자' 형태로 저장된 내용을 변환된 식으로 복원
while ( $str =~ s/(TERM\d+)/$save{$1}/g ) {}
 
# 제일 바깥쪽에 추가했던 괄호 제거
$str =~ s/^\( //;
$str =~ s/ \)$//;
 
print $str, "\n";
 
exit;
 
 
# 괄호로 둘러싸인 부분식을 저장하는 함수
sub save {
    my ($open, $expr, $close) = @_;
 
    my %opword = (
        '-' => 'NOT',
        '+' => 'OR',
        '&' => 'AND',
    );
    my $converted;
 
    # -,+,& 중에 하나가 들어있는지 추출
    my ($op) = $expr =~ /([-+&])/;
 
    if ( $op ) {
        # 부분식 안에 연산자가 들어있다면 그 연산자를 구분자로 해서
        # 부분식을 여러 항들로 쪼갠다
        my @terms = split /\s*\Q$op\E\s*/, $expr;
 
        if ( @terms == 2 ) {
            # 항이 두 개면 연산자를 가운데
            $converted = "$terms[0] $opword{$op} $terms[1]";
        }
        else {
            # 항이 세 개 이상이거나,
            # 그럴리는 없겠지만 항이 1개거나 없는 경우
            # 연산자를 앞에
            $converted = "$opword{$op} @terms";
        }
    }
    else {
        # 연산자가 들어 있지 않은 단항인 경우
        $converted = $expr;
    }
 
    my $key = "TERM" . ++$idx;
    $save{$key} = "$open $converted $close";
    return $key;
}

좋은 하루 되세요!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.