자체 개발 계산기 (3) - 140 줄 코드 해결 Token 분석
acosd(2)+cosd(30)*12+1.23E-21
간단 한 처 리 를 위해 서 는 실제 계산 하기 전에 입력 을 하나의 단어 (Token) 로 분해 합 니 다.예 를 들 어 위의 내용 은 처 리 를 거 쳐 아래 의 형식 이 될 수 있다 면 쉽게 처리 할 수 있다.
acosd,(,2,),+,cosd,(,30,),*,12+1.23E-21
여기 서 acosd, cosd, (,), * 와 같은 요 소 는 간단 한 문자열 비 교 를 통 해 해결 할 수 있 습 니 다.하지만 숫자 와 마지막 e 지 수 는 그리 간단 하지 않다.물론 이것 이 프로 그래 밍 기본 기 를 보 여줄 기회 라 고 생각한다 면 아무 도 당신 을 막 지 않 지만 이 소프트웨어 에서 우 리 는 정규 표현 식 으로 이 문 제 를 해결 했다.
예 를 들 어 e 지 수 는 다음 과 같이 정의 할 수 있다.
"((\\.[0-9]+)|([0-9]+(\\.[0-9]*)?))[eE][+-]?[0-9]+"
일반 형식의 소수:
"(\\.[0-9]+)|([0-9]+\\.[0-9]*)"
정 수 는 더욱 간단 하 다.
"[0-9]+"
이렇게 되면 우 리 는 + / - 호 처럼 다른 요 소 를 처리 할 수 있다.정규 표현 식 의 문법 은 모두 가 [정규 표현 식 (제3 판) 에 정통 함] 이라는 책 을 참조 할 수 있다.실제 내용 에 대해 서 는 다른 글 을 보 는 것 을 권장 합 니 다.
자체 개발 계산기 (0) - 확장 바 커 스 패 러 다 임 (EBNF)
다음은 소스 코드 를 보 겠 습 니 다.사용 하 는 곳 부터 보 세 요.
- QList<Token*> CalculateEngine::analyzeToken(QString strQuestion)
- {
- typedef TokenAnalyzer<Token, Token::EType, QList<Token*>::iterator> MyAnalyzer;
-
- class MyFactory : public MyAnalyzer::TokenPatternFactory
- {
- virtual int createPatterns(QList<MyAnalyzer::TokenPattern*>& list) const
- {
- FunctionManager* manager = FunctionManager::getInstance();
- QList<QString> functions = manager->functions();
-
- QString funPattern;
- foreach(QString funName, functions)
- {
- if(funPattern.length() > 0)
- {
- funPattern += "|";
- }
- funPattern += funName;
- }
- list.append(new MyAnalyzer::TokenPattern(Token::FunctionName, funPattern));
-
- list.append(new MyAnalyzer::TokenPattern(Token::Number, "((\\.[0-9]+)|([0-9]+(\\.[0-9]*)?))[eE][+-]?[0-9]+"));
- list.append(new MyAnalyzer::TokenPattern(Token::Number, "(\\.[0-9]+)|([0-9]+\\.[0-9]*)"));
- list.append(new MyAnalyzer::TokenPattern(Token::Number, "[0-9]+"));
- list.append(new MyAnalyzer::TokenPattern(Token::Operator, "[-+*/%]"));
- list.append(new MyAnalyzer::TokenPattern(Token::Parenthese, "[()]"));
- list.append(new MyAnalyzer::TokenPattern(Token::Comma, ","));
-
- return list.count();
- }
- };
-
- MyFactory factory;
-
- MyAnalyzer analyzer;
- QList<Token*> tokenList = analyzer.analyzeToken(strQuestion, &factory);
- return tokenList;
- }
정규 표현 식 을 준비 하 는 데 많은 시간 을 들 인 후에 TokenAnalyzer:: analyzer Token 을 호출 하면 됩 니 다.다음은 TokenAnalyzer 의 소스 코드 입 니 다.Token 의 유형 이 수요 에 따라 다 를 수 있 음 을 고려 하여 템 플 릿 류 를 사 용 했 습 니 다.
- #ifndef TOKENANALYZER_H
- #define TOKENANALYZER_H
- #include<QString>
- #include<QList>
- #include<QRegExp>
- template<typename Token, typename TokenType, typename TokenIterator>
- class TokenAnalyzer
- {
- public:
- struct TokenPattern
- {
- TokenPattern(TokenType _type, QString _regex):regex(_regex),type(_type){}
- QRegExp regex;
- TokenType type;
- };
- class TokenPatternFactory
- {
- public:
- virtual int createPatterns(QList<TokenPattern*>& list) const= 0;
- };
- TokenAnalyzer(){}
- QList<Token*> analyzeToken(QString strInput, const TokenPatternFactory* factory);
- private:
- struct Context
- {
- Context(QList<Token*>& list, TokenIterator& _it, TokenPattern& _pattern, QString& _content)
- :tokenList(list), it(_it), pattern(_pattern), content(_content){}
- QList<Token*>& tokenList;
- TokenIterator& it;
- TokenPattern& pattern;
- QString& content;
- };
- void analyzeContent(Context& context);
- };
- template<typename Token, typename TokenType, typename TokenIterator>
- QList<Token*> TokenAnalyzer<Token, TokenType, TokenIterator>::analyzeToken(QString strInput, const TokenPatternFactory* factory)
- {
- QList<Token*> tokenList;
- tokenList.append(new Token(strInput));
- QList<TokenPattern*> list;
- factory->createPatterns(list);
- foreach(TokenPattern* pattern, list)
- {
- TokenIterator it = tokenList.begin();
- while(it != tokenList.end())
- {
- Token* token = *it;
- if(token->isNoType())
- {
- QString content = token->getContent();
- Context context(tokenList, it, *pattern, content);
- analyzeContent(context);
- }
- it++;
- }
- }
- return tokenList;
- }
- template<typename Token, typename TokenType, typename TokenIterator>
- void TokenAnalyzer<Token, TokenType, TokenIterator>::analyzeContent(Context& context)
- {
- Token* token = *context.it;
- int tokenBegin = context.content.indexOf(context.pattern.regex);
- if(tokenBegin != -1)
- {
- int matchedLength = context.pattern.regex.matchedLength();
- int tokenEnd = tokenBegin + matchedLength;
- if(tokenBegin > 0)
- {
- context.it = context.tokenList.insert(context.it, new Token(context.content.left(tokenBegin)));
- context.it++;
- }
- if(tokenEnd < context.content.length())
- {
- context.it = context.tokenList.insert(context.it,
- new Token(context.pattern.type, context.content.mid(tokenBegin, matchedLength)));
- context.it++;
- context.content.remove(0, tokenEnd);
- analyzeContent(context);
- }
- else
- {
- token->setContent(context.content.mid(tokenBegin, tokenEnd));
- token->setType(context.pattern.type);
- context.content.remove(0, tokenEnd);
- }
- }
- else
- {
- token->setContent(context.content);
- }
- }
- #endif // TOKENANALYZER_H
정규 표현 식 을 정의 하 는 부분 을 포함 하면 딱 120 줄 입 니 다.
물론 빠 질 수 없다. 진정한 주인공 Token 류.
- class Token
- {
- public:
- enum EType
- {
- NoType,
- Operator,
- Number,
- FunctionName
- };
-
- Token(EType type, QString content);
- Token(QString content);
- EType getType();
- QString getContent();
- void setType(EType type);
- bool isNoType();
- void setContent(QString content);
-
- private:
- EType mType;
- QString mContent;
- };
기타 관련 글 은 참고 하 시기 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
awk 상용 명령awk 는 모든 입력 줄 을 하나의 기록 으로 인식 하고 그 줄 의 모든 단어 도 메 인 을 하나의 필드 로 인식 합 니 다. ARGC 명령 줄 에 awk 스 크 립 트 가 들 어 오 는 매개...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.