TNB Library
TnbRegularExpression.h
[詳解]
1#pragma once
13#include "TnbStrVector.h"
14
15
16
17//T-TestCaseコードカバレッジDisable
18#pragma comment(user,"T-Coverage Disable")
19
20
21
22#ifndef _TnbDOXYGEN //Document作成用シンボル
24#if 0
25#define _REGEX_TRACE0(S) TRACE0(S)
26#define _REGEX_TRACE1(S,P1) TRACE1(S, P1)
27#define _REGEX_TRACE2(S,P1,P2) TRACE2(S,P1,P2)
28#define _REGEX_TRACE3(S,P1,P2,P3) TRACE3(S,P1,P2,P3)
29#else
30#define _REGEX_TRACE0(S)
31#define _REGEX_TRACE1(S,P1)
32#define _REGEX_TRACE2(S,P1,P2)
33#define _REGEX_TRACE3(S,P1,P2,P3)
34#endif
35#endif // _TnbDOXYGEN
36
37
38
39//TNB Library
40namespace TNB
41{
42
43
44
161template<typename TYP, typename ITE = const TYP*>
163{
164public:
165
172 {
174// MULTILINE = _BIT(1), ///< 「複数行モードを有効」オプション
175 };
176
177private:
178
179 #ifndef _TnbDOXYGEN //Document作成用シンボル
180
182 class CAbstractChecker
183 {
184 public:
186 struct TPairIterator
187 {
188 ITE top;
189 ITE end;
190 bool boValidEnd;
192 TPairIterator(ITE s = ITE(), ITE e = ITE(), bool r = false)
193 : top(s), end(e), boValidEnd(r)
194 {
195 }
197 void SetEnd(ITE e)
198 {
199 end = e;
200 boValidEnd = true;
201 }
202 };
204 struct TStaticParam
205 {
206 ITE end;
207 CVectorT<TPairIterator> groupIterators;
208 ITE tempEnd;
209 ITE outsizeEnd;
210 DWORD option;
212 TStaticParam(void) : end(ITE()), tempEnd(ITE()), option(0)
213 {
214 }
215 size_t GetSize(void) const
216 {
217 return groupIterators.GetSize();
218 }
219 TPairIterator At(INDEX index) const
220 {
221 const TPairIterator& ii = groupIterators.At(index);
222 TPairIterator r((index == 0 && outsizeEnd != ITE()) ? outsizeEnd : ii.top);
223 r.SetEnd(ii.boValidEnd ? ii.end : tempEnd);
224 return r;
225 }
227 CVectorT< CStrT<TYP> > ToStrings(void) const
228 {
230 loop ( i, GetSize() )
231 {
232 const TPairIterator& ii = At(i);
233 vs.Add(CStrT<TYP>::FromIterator(ii.top, ii.end));
234 }
235 return vs;
236 }
237 };
239 struct TParam
240 {
241 ITE cur;
242 ITE top;
243 TStaticParam* pt;
245 TParam(ITE c, ITE t, ITE e, TStaticParam* p) : cur(c), top(t), pt(p)
246 {
247 pt->end = e;
248 pt->tempEnd = e;
249 pt->outsizeEnd = ITE();
250 }
252 bool IsTerminate(void) const
253 {
254 return (cur == pt->end) ? true : (*cur == 0);
255 }
257 size_t GetWord(WORD& _ch)
258 {
259 if ( IsTerminate() ){ return INVALID_SIZE; }
260 WORD c = *cur;
261 size_t l = STRLIB::GetCharSize(*cur);
262 if ( l == 2 )
263 {
264 ASSERT( sizeof(TYP) == 1 );
265 cur++;
266 if ( IsTerminate() ){ return INVALID_SIZE; }
267 c = static_cast<WORD>(((c & 0xFF) << 8) | ((*cur) & 0xFF));
268 }
269 _ch = c;
270 return l;
271 }
273 void StepCur(size_t l)
274 {
275 if ( l != INVALID_SIZE )
276 {
277 loop ( i, l )
278 {
279 ASSERTLIB( cur != pt->end );
280 cur++;
281 }
282 }
283 }
285 bool EqualChar(TYP c1, TYP c2)
286 {
287 if ( (pt->option & IGNORECASE) != 0 )
288 {
289 if ( c1 >= 'A' && c1 <= 'Z' ) { c1 |= 0x20; }
290 if ( c2 >= 'A' && c2 <= 'Z' ) { c2 |= 0x20; }
291 }
292 return c1 == c2;
293 }
294 };
296 virtual ~CAbstractChecker(void){}
303 virtual size_t Check(TParam ip) const = 0;
304 };
305
307 typedef CPointerHandleT<CAbstractChecker> CCheckerPtr;
308
310 typedef CVectorT<CCheckerPtr> CCheckerPtrsVector;
311
312 //================================================
313
317 class CEqualChar : public CAbstractChecker
318 {
319 WORD m_char;
320 public:
322 CEqualChar(WORD c) : m_char(c)
323 {
324 }
326 virtual size_t Check(TParam ip) const
327 {
328 _REGEX_TRACE1( "正規表現 比較 ; EqualChar [0x%X]\n", m_char );
329 WORD c;
330 size_t l = ip.GetWord(c);
331 if ( l == INVALID_SIZE ){ return INVALID_SIZE; }
332 bool r = ip.EqualChar(static_cast<TYP>(c), static_cast<TYP>(m_char));
333 return r ? l : INVALID_SIZE;
334 }
335 };
336
341 class CRangeChar : public CAbstractChecker
342 {
343 WORD m_top;
344 WORD m_bottom;
345 bool m_reverse;
346 public:
348 CRangeChar(WORD top, WORD bottom, bool boIsReverse = false)
349 : m_top(top), m_bottom(bottom), m_reverse(boIsReverse)
350 {
351 if ( m_top > m_bottom ) { Swap(m_top, m_bottom); }
352 }
354 virtual size_t Check(TParam ip) const
355 {
356 _REGEX_TRACE3( "正規表現 比較 ; RangeChar ['%c' - '%c' (%d)]\n", m_top, m_bottom, m_reverse );
357 WORD c;
358 size_t l = ip.GetWord(c);
359 if ( l == INVALID_SIZE ){ return INVALID_SIZE; }
360 if ( (ip.pt->option & IGNORECASE) != 0 )
361 {
362 if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') )
363 {
364 c |= 0x20;
365 return ((c < (m_top|0x20) || c > (m_bottom|0x20)) ^ m_reverse) ? INVALID_SIZE : l;
366 }
367 }
368 return ((c < m_top || c > m_bottom) ^ m_reverse) ? INVALID_SIZE : l;
369 }
370 };
371
374 class CAnythingChar : public CAbstractChecker
375 {
376 public:
378 virtual size_t Check(TParam ip) const
379 {
380 _REGEX_TRACE0( "正規表現 比較 ; AnythingChar\n" );
381 return ip.IsTerminate() ? INVALID_SIZE : (STRLIB::GetCharSize(*ip.cur));
382 }
383 };
384
387 class CTop : public CAbstractChecker
388 {
389 public:
391 virtual size_t Check(TParam ip) const
392 {
393 _REGEX_TRACE0( "正規表現 比較 ; Top\n" );
394 return (ip.cur == ip.top) ? 0 : INVALID_SIZE;
395 }
396 };
397
400 class CEnd : public CAbstractChecker
401 {
402 public:
404 virtual size_t Check(TParam ip) const
405 {
406 _REGEX_TRACE0( "正規表現 比較 ; End\n" );
407 return ip.IsTerminate() ? 0 : INVALID_SIZE;
408 }
409 };
410
413 class CFrontWord : public CAbstractChecker
414 {
415 INDEX m_index;
416 public:
417 CFrontWord(INDEX i) : m_index(i)
418 {
419 }
421 virtual size_t Check(TParam ip) const
422 {
423 _REGEX_TRACE1( "正規表現 比較 ; FrontWord (index = %d)\n", m_index );
424 if ( ip.pt->groupIterators.GetSize() <= m_index )
425 {
426 return INVALID_SIZE;
427 }
428 const TPairIterator& ii = ip.pt->groupIterators.At(m_index);
429 ITE is = ii.top;
430 ITE ie = ii.boValidEnd ? ii.end : ip.pt->tempEnd;
431// if ( ! ii.boValidEnd )
432// {
433// CStrT<TYP> s = CStrT<TYP>::FromIterator(is, ie);
434// TRACE2( "[%s] [%s]\n", CStr(s), CStr(ip.cur) );
435// }
436 size_t r = 0;
437 while ( is != ie )
438 {
439 if ( *is == 0 ) { break; }
440 if ( ip.cur == ip.pt->end ) { return INVALID_SIZE; }
441 if ( ! ip.EqualChar(*is++, *ip.cur++) ){ return INVALID_SIZE; }
442 r++;
443 }
444 return r;
445 }
446 };
447
448 //================================================
449
454 class CGroupChecker : public CAbstractChecker
455 {
456 public:
457 enum EType
458 {
459 ET_Non,
460 ET_RefGroup,
461 ET_NoRefGroup,
462 ET_AfterEqu,
463 ET_AfterNeq,
464 ET_BeforeEqu,
465 ET_BeforeNeq,
466 };
467 private:
468 EType m_type;
469 CCheckerPtr m_checker;
470 public:
472 CGroupChecker(CCheckerPtr cp, EType y = ET_RefGroup) : m_checker(cp), m_type(y)
473 {
474 ASSERTLIB( y != ET_Non );
475 }
477 virtual size_t Check(TParam ip) const
478 {
479 _REGEX_TRACE1( "正規表現 比較 ; GroupChecker (%d)\n", m_type );
480 if ( m_type == ET_RefGroup ) // (regex) グループ(前方参照あり)
481 {
482 INDEX insertIndex = ip.pt->groupIterators.GetSize();
483 ip.pt->groupIterators.Add(TPairIterator(ip.cur, ip.pt->end)); //ダミーデータを追加しておく。
484 size_t l = m_checker->Check(ip);
485 if ( l != INVALID_SIZE )
486 {
487 ip.StepCur(l);
488 ip.pt->groupIterators.Ref(insertIndex).SetEnd(ip.cur);
489 }
490 return l;
491 }
492 size_t l = m_checker->Check(ip);
493 switch ( m_type )
494 {
495 case ET_RefGroup: // (regex) グループ(前方参照あり)
496 ip.StepCur(l);
497 break;
498 case ET_NoRefGroup: // (?:regex) グループ(前方参照なし)
499 ip.StepCur(l);
500 break;
501 case ET_AfterEqu: // regex(?=regex) 肯定先読み
502 l = (l != INVALID_SIZE) ? 0 : INVALID_SIZE;
503 break;
504 case ET_AfterNeq: // regex(?!regex) 否定先読み
505 l = (l == INVALID_SIZE) ? 0 : INVALID_SIZE;
506 break;
507 case ET_BeforeEqu: // (?<=regex)regex 肯定後読み
508 case ET_BeforeNeq: // (?<!regex)regex 否定後読み
509 if ( ip.pt->outsizeEnd != ITE() )
510 {
511 l = INVALID_SIZE;
512 }
513 else
514 {
515 if ( l != INVALID_SIZE )
516 {
517 ip.StepCur(l);
518 ip.pt->outsizeEnd = ip.cur;
519 }
520 if ( m_type == ET_BeforeNeq ) // (?<!regex)regex 否定後読み
521 {
522 l = (l == INVALID_SIZE) ? 0 : INVALID_SIZE;
523 }
524 }
525 break;
526 default:
527 ASSERTLIB( false );
528 break;
529 }
530 return l;
531 }
532 };
533
537 class CFindChecker : public CAbstractChecker
538 {
539 CCheckerPtr m_loopChecker;
540 CCheckerPtr m_markChecker;
541 int m_min;
542 int m_max;
543 bool m_isMini;
544 public:
546 CFindChecker(CCheckerPtr loopChk, int min, int max, bool mini)
547 : m_loopChecker(loopChk), m_min(min), m_max(max), m_isMini(mini)
548 {
549 }
550 void SetMarkChecker(CCheckerPtr cp)
551 {
552 ASSERTLIB( this != cp.operator->() );
553 m_markChecker = cp;
554 }
556 virtual size_t Check(TParam ip) const
557 {
558 CVectorT<TPairIterator> bakGrpItes;
559 ITE bakIte = ip.pt->tempEnd;
560 size_t ns = ip.pt->groupIterators.GetSize();
561 ip.pt->tempEnd = ip.cur;
562 if ( m_markChecker.IsNull() )
563 {
564 _REGEX_TRACE2( "正規表現 比較 ; FindChecker(%d 〜 %d) 「ENDかMAXまで」\n", m_min, m_max);
565 INDEX findingIndex = 0;
566 int foundCount = 0;
567 while ( true )
568 {
569 if ( m_max >= 0 && foundCount == m_max ) { break; }
570 if ( m_isMini && m_min <= foundCount ) { break; }
571 size_t l = m_loopChecker->Check(ip);
572 if ( ns < ip.pt->groupIterators.GetSize() )
573 {
574 if ( l != INVALID_SIZE )
575 {
576 bakGrpItes = ip.pt->groupIterators;
577 }
578 ip.pt->groupIterators.SetSize(ns);
579 }
580 if ( l == INVALID_SIZE ) { break; }
581 ip.StepCur(l);
582 ip.pt->tempEnd = ip.cur;
583 foundCount++;
584 findingIndex += l;
585 }
586 ip.pt->tempEnd = bakIte;
587 if ( ! bakGrpItes.IsEmpty() )
588 {
589 ip.pt->groupIterators = bakGrpItes;
590 }
591 return (foundCount < m_min) ? INVALID_SIZE : findingIndex;
592 }
593 _REGEX_TRACE2( "正規表現 比較 ; FindChecker(%d 〜 %d) 「次一致」\n", m_min, m_max);
594 INDEX findingIndex = 0;
595 INDEX foundIndex = INVALID_INDEX;
596 int foundCount = 0;
597 while ( ! ip.IsTerminate() )
598 {
599 if ( foundCount >= m_min )
600 {
601 size_t l = m_markChecker->Check(ip);
602 if ( l != INVALID_SIZE )
603 {
604 foundIndex = findingIndex;
605 if ( m_isMini ) { break; }
606 }
607 ns = ip.pt->groupIterators.GetSize();
608 }
609 if ( m_max >= 0 && foundCount == m_max ) { break; }
610 size_t l = m_loopChecker->Check(ip);
611 if ( ns < ip.pt->groupIterators.GetSize() )
612 {
613 if ( l != INVALID_SIZE )
614 {
615 bakGrpItes = ip.pt->groupIterators;
616 }
617 ip.pt->groupIterators.SetSize(ns);
618 }
619 if ( l == INVALID_SIZE ) { break; }
620 ip.StepCur(l);
621 ip.pt->tempEnd = ip.cur;
622 foundCount++;
623 findingIndex += l;
624 }
625 ip.pt->tempEnd = bakIte;
626 if ( ! bakGrpItes.IsEmpty() )
627 {
628 ip.pt->groupIterators = bakGrpItes;
629 }
630 return (foundCount < m_min) ? INVALID_SIZE : foundIndex;
631 }
632 };
633
637 class CAnyChecker : public CAbstractChecker
638 {
639 protected:
640 CCheckerPtrsVector m_checkers;
641 public:
643 virtual bool IsMeaningless(void) const
644 {
645 return m_checkers.GetSize() == 1;
646 }
648 virtual CCheckerPtr& Top(void)
649 {
650 return m_checkers[0];
651 }
653 virtual void Add(CCheckerPtr chk)
654 {
655 m_checkers.Add(chk);
656 }
658 virtual size_t Check(TParam ip) const
659 {
660 _REGEX_TRACE1( "正規表現 比較 ; AnyChecker(%d)\n", m_checkers.GetSize() );
661 size_t r = INVALID_SIZE;
662 loop ( i, m_checkers.GetSize() )
663 {
664 size_t l = m_checkers[i]->Check(ip);
665 if ( l != INVALID_SIZE )
666 {
667 if ( r == INVALID_SIZE ) { r = 0; }
668 if ( r < l ) { r = l; }
669 }
670 }
671 return r;
672 }
673 };
674
678 class CNotAnyChecker : public CAnyChecker
679 {
680 public:
682 virtual bool IsMeaningless(void) const
683 {
684 return false; //このクラスは絶対「意味がある」
685 }
687 virtual size_t Check(TParam ip) const
688 {
689 _REGEX_TRACE1( "正規表現 比較 ; NotAnyChecker(%d)\n", m_checkers.GetSize() );
690 if ( ip.IsTerminate() ){ return INVALID_SIZE; }
691 loop ( i, m_checkers.GetSize() )
692 {
693 size_t l = m_checkers[i]->Check(ip);
694 if ( l != INVALID_SIZE ) { return INVALID_SIZE; }
695 }
696 return STRLIB::GetCharSize(*ip.cur);
697 }
698 };
699
704 class CBesidesChecker : public CAnyChecker
705 {
706 public:
708 virtual size_t Check(TParam ip) const
709 {
710 _REGEX_TRACE1( "正規表現 比較 ; BesidesChecker(%d)\n", m_checkers.GetSize() );
711 size_t r = INVALID_SIZE;
712 loop ( i, m_checkers.GetSize() )
713 {
714 size_t l = m_checkers[i]->Check(ip);
715 if ( l == INVALID_SIZE ) { return INVALID_SIZE; }
716 if ( r == INVALID_SIZE )
717 {
718 r = l;
719 }
720 else if ( r != l )
721 {
722 return INVALID_SIZE;
723 }
724 }
725 ip.StepCur(r);
726 return r;
727 }
728 };
729
732 class CLineChecker : public CAnyChecker
733 {
734 public:
736 virtual size_t Check(TParam ip) const
737 {
738 _REGEX_TRACE1( "正規表現 比較 ; LineChecker(%d)\n", m_checkers.GetSize() );
739 ASSERTLIB( m_checkers.GetSize() != 0 );
740 size_t r = 0; //一致したトータル長さ
741 loop ( i, m_checkers.GetSize() )
742 {
743 size_t l = m_checkers[i]->Check(ip);
744 if ( l == INVALID_SIZE ) { return INVALID_SIZE; }
745 ip.StepCur(l);
746 r += l;
747 }
748 return r;
749 }
750 };
751
752 #endif // _TnbDOXYGEN
753
754 //================================================
755
756 CCheckerPtr m_root;
757 CStrT<TYP> m_base;
758 CFindChecker* m_pLastFindChecker;
759 DWORD m_option;
760
762 void m_RemoveAll(void)
763 {
764 m_root.Null();
765 m_base.Empty();
766 m_pLastFindChecker = NULL;
767 }
768
769 /*
770 * _lpsz は{ の次の文字を指している
771 */
772 bool m_SubNum(int& _r, const WORD*& _lpsz)
773 {
774 _r = -1;
775 const WORD* P =_lpsz;
776 while( *P >= '0' && *P <= '9' )
777 {
778 if ( _r < 0 ) { _r = 0; }
779 _r *= 10;
780 _r += (*P - '0');
781 P++;
782 }
783 if ( _r >= 0 )
784 {
785 _lpsz = P;
786 return true;
787 }
788 return false;
789 }
790
791 /*
792 * _lpsz は{ の文字を指している
793 * _checker には繰り返すチェッカーが入っている。
794 */
795 bool m_SubCnt(int& _min, int& _max, const WORD*& _lpsz)
796 {
797 const WORD* P =_lpsz;
798 int r;
799 if ( *P++ == '{' )
800 {
801 if ( m_SubNum(r, P) )
802 {
803 if ( *P != ',' )
804 {
805 _min = r;
806 _max = r;
807 }
808 else
809 {
810 _min = r;
811 P++;
812 if ( m_SubNum(r, P) )
813 {
814 _max = r;
815 }
816 }
817 if ( *P == '}' )
818 {
819 _lpsz = P + 1;
820 return true;
821 }
822 }
823 }
824 return false;
825 }
826
831 CCheckerPtr m_ChkChecker(CAnyChecker* P)
832 {
833 if ( P->IsMeaningless() )
834 {
835 CCheckerPtr c = P->Top();
836 delete P;
837 return c;
838 }
839 return P;
840 }
841
842 /*
843 * isAny が false なら
844 * " " , ( ) 内のチェック用
845 * @note ”か ) か \0 までをチェック
846 * isAny が true なら
847 * [ ]内のチェック用
848 * @note ]までをチェック
849 *
850 * @param _lpsz ”か(か [ の次の文字ポインタ。成功時、終端の文字ポインタになっています。
851 */
852 bool m_Sub(CCheckerPtr& _checker, const WORD*& _lpsz, bool isAny)
853 {
854 CFindChecker* pLastFindChecker = m_pLastFindChecker;
855 m_pLastFindChecker = NULL;
856 CAnyChecker* pCheckers = NULL;
857 const WORD* P = _lpsz;
858 if ( isAny )
859 {
860 if ( *P == '^' )
861 {
862 P++;
863 pCheckers = new CNotAnyChecker();
864 }
865 else
866 {
867 pCheckers = new CAnyChecker();
868 }
869 }
870 else
871 {
872 pCheckers = new CLineChecker();
873 }
874 bool isError = false;
875 bool isFirst = true;
876 WORD rangeChar = 0;
877 while ( ! isError )
878 {
879 WORD c = *P++;
880 CCheckerPtr chk;
881 CGroupChecker::EType groupType = CGroupChecker::ET_Non;
882 CFindChecker* pLastFind = NULL;
883 if ( ! isAny )
884 {
885 //Any以外でのみ有効なもの
886 // [〜]ないではでは無効なもの
887 switch ( c )
888 {
889 case '.':
890 chk = new CAnythingChar();
891 break;
892 case '(':
893 groupType = CGroupChecker::ET_RefGroup;
894 if ( *P == '?' )
895 {
896 if ( P[1] == ':' )
897 {
898 groupType = CGroupChecker::ET_NoRefGroup;
899 P += 2;
900 }
901 else if ( P[1] == '=' )
902 {
903 groupType = CGroupChecker::ET_AfterEqu;
904 P += 2;
905 }
906 else if ( P[1] == '!' )
907 {
908 groupType = CGroupChecker::ET_AfterNeq;
909 P += 2;
910 }
911 else if ( P[1] == '<' && P[2] == '=' )
912 {
913 groupType = CGroupChecker::ET_BeforeEqu;
914 P += 3;
915 }
916 else if ( P[1] == '<' && P[2] == '!' )
917 {
918 groupType = CGroupChecker::ET_BeforeNeq;
919 P += 3;
920 }
921 }
922 if ( ! m_Sub(chk, P, false) || *P != ')' )
923 {
924 groupType = CGroupChecker::ET_Non;
925 isError = true;
926 break;
927 }
928 P++;
929 pLastFind = m_pLastFindChecker;
930 m_pLastFindChecker = NULL;
931 break;
932 case ')':
933 _checker = m_ChkChecker(pCheckers);
934 if ( pLastFindChecker != NULL )
935 {
936 pLastFindChecker->SetMarkChecker(_checker);
937 }
938 _lpsz = P - 1;
939 return true;
940 case '|':
941 {
942 CFindChecker* pCkBack = m_pLastFindChecker;
943 m_pLastFindChecker = NULL;
944 CCheckerPtr cp;
945 if ( m_Sub(cp, P, false) && (*P == 0 || *P == ')') )
946 {
947 m_pLastFindChecker = pCkBack;
948 CAnyChecker* a = new CAnyChecker();
949 a->Add(m_ChkChecker(pCheckers));
950 a->Add(cp);
951 _checker = a;
952 if ( pLastFindChecker != NULL )
953 {
954 pLastFindChecker->SetMarkChecker(_checker);
955 }
956 _lpsz = P;
957 return true;
958 }
959 }
960 isError = true;
961 break;
962 case '^':
963 if ( isFirst )
964 {
965 chk = new CTop();
966 }
967 break;
968 case '$':
969 if ( *P == 0 )
970 {
971 chk = new CEnd();
972 }
973 break;
974 default:
975 break;
976 }
977 }
978 if ( isError ) { break; }
979 //--
980 if ( chk.IsNull() )
981 {
982 switch ( c )
983 {
984 case '[':
985 if ( isFirst && isAny )
986 {
987 ;
988 }
989 else if ( ! m_Sub(chk, P, true) || *P != ']' )
990 {
991 isError = true;
992 }
993 else
994 {
995 P++;
996 pLastFind = m_pLastFindChecker;
997 m_pLastFindChecker = NULL;
998 }
999 break;
1000 case ']':
1001 if ( isFirst && isAny )
1002 {
1003 break;
1004 }
1005 _checker = m_ChkChecker(pCheckers);
1006 if ( pLastFindChecker != NULL )
1007 {
1008 pLastFindChecker->SetMarkChecker(_checker);
1009 }
1010 _lpsz = P - 1;
1011 return true;
1012 case 0:
1013 _checker = m_ChkChecker(pCheckers);
1014 if ( pLastFindChecker != NULL )
1015 {
1016 pLastFindChecker->SetMarkChecker(_checker);
1017 }
1018 _lpsz = P - 1;
1019 return true;
1020 case '&':
1021 if ( isAny && *P == '&' )
1022 {
1023 P++;
1024 CFindChecker* pCkBack = m_pLastFindChecker;
1025 m_pLastFindChecker = NULL;
1026 CCheckerPtr cp;
1027 if ( m_Sub(cp, P, false) && *P == ']' )
1028 {
1029 m_pLastFindChecker = pCkBack;
1030 CAnyChecker* a = new CBesidesChecker();
1031 a->Add(m_ChkChecker(pCheckers));
1032 a->Add(cp);
1033 _checker = a;
1034 if ( pLastFindChecker != NULL )
1035 {
1036 pLastFindChecker->SetMarkChecker(_checker);
1037 }
1038 _lpsz = P;
1039 return true;
1040 }
1041 isError = true;
1042 }
1043 break;
1044 case '\\':
1045 ASSERTLIB( chk.IsNull() );
1046 c = *P++;
1047 switch ( c )
1048 {
1049 case 'd': // 数字([0-9])
1050 case 'D': // 数字以外([~0-9])
1051 chk = new CRangeChar('0', '9', (c == 'D'));
1052 break;
1053 case 's': // 空白(\t\n\x0B\f\r) ※全角の含む?
1054 case 'S': // 空白以外([~\s])
1055 {
1056 CAnyChecker* pAny = (c == 's') ? new CAnyChecker() : new CNotAnyChecker();
1057 const char ap[] = { ' ', '\t', '\n', '\x0B', '\f', '\r' };
1058 loop ( i, countof(ap) )
1059 {
1060 pAny->Add(new CEqualChar(ap[i]));
1061 }
1062 chk = pAny;
1063 }
1064 break;
1065 case 'w': // 単語([a-zA-Z0-9_])
1066 case 'W': // 単語以外([~\W])
1067 {
1068 CAnyChecker* pAny = (c == 'w') ? new CAnyChecker() : new CNotAnyChecker();
1069 pAny->Add(new CRangeChar('a', 'z'));
1070 pAny->Add(new CRangeChar('A', 'Z'));
1071 pAny->Add(new CRangeChar('0', '9'));
1072 pAny->Add(new CEqualChar('_'));
1073 chk = pAny;
1074 }
1075 break;
1076 default:
1077 P -= 2;
1078 int r = STRLIB::EscCharToInt(P);
1079 if ( r >= 0 )
1080 {
1081 c = static_cast<WORD>(r);
1082 }
1083 else
1084 {
1085 P += 2;
1086 if ( c >= '0' && c <= '9' )
1087 {
1088 chk = new CFrontWord(c - '0');
1089 }
1090 }
1091 break;
1092 }
1093 break;
1094 default:
1095 break;
1096 }
1097 }
1098 if ( isError ) { break; }
1099 //--
1100 if ( chk.IsNull() )
1101 {
1102 if ( *P == '-' )
1103 {
1104 P++;
1105 WORD d = *P++;
1106 if ( d == '\\' )
1107 {
1108 --P;
1109 int r = STRLIB::EscCharToInt(P);
1110 if ( r >= 0 )
1111 {
1112 d = static_cast<WORD>(r);
1113 }
1114 else
1115 {
1116 isError = true;
1117 }
1118 }
1119 chk = new CRangeChar(c, d);
1120 }
1121 else
1122 {
1123 chk = new CEqualChar(c);
1124 }
1125 }
1126 if ( isError ) { break; }
1127 //--
1128 if ( ! chk.IsNull() )
1129 {
1130 if ( rangeChar != 0 )
1131 {
1132 isError = true;
1133 }
1134 else if ( ! isAny )
1135 {
1136 int min = -1;
1137 int max = -1;
1138 switch ( *P )
1139 {
1140 case '*': //0個以上
1141 min = 0;
1142 P++;
1143 break;
1144 case '+': //1個以上
1145 min = 1;
1146 P++;
1147 break;
1148 case '?': //0個か1個
1149 min = 0;
1150 max = 1;
1151 P++;
1152 break;
1153 case '{': // {a} a個のならび、{a,} a個以上、{a,b} a個〜b個。
1154 if ( ! m_SubCnt(min, max, P) )
1155 {
1156 isError = true;
1157 min = -1; //無駄な処理しないように
1158 }
1159 break;
1160 default:
1161 break;
1162 }
1163 if ( min >= 0 )
1164 {
1165 bool isMini = false;
1166 if ( *P == '?' )
1167 {
1168 P++;
1169 isMini = true;
1170 }
1171 if ( groupType != CGroupChecker::ET_Non )
1172 {
1173 chk = new CGroupChecker(chk, groupType);
1174 groupType = CGroupChecker::ET_Non;
1175 }
1176 pLastFind = new CFindChecker(chk, min, max, isMini);
1177 chk = pLastFind;
1178 }
1179 }
1180 if ( ! chk.IsNull() )
1181 {
1182 if ( groupType != CGroupChecker::ET_Non )
1183 {
1184 chk = new CGroupChecker(chk, groupType);
1185 groupType = CGroupChecker::ET_Non;
1186 }
1187 if ( m_pLastFindChecker != NULL )
1188 {
1189 m_pLastFindChecker->SetMarkChecker(chk);
1190 }
1191 m_pLastFindChecker = pLastFind;
1192 pLastFind = NULL;
1193 pCheckers->Add(chk);
1194 chk.Null();
1195 }
1196 }
1197 isFirst = false;
1198 }
1199 delete pCheckers;
1200 return false;
1201 }
1202
1211 size_t m_MatchSize(typename CAbstractChecker::TParam ip, CVectorT< CStrT<TYP> >* pGroupStr) const
1212 {
1213 if ( m_root.IsNull() )
1214 {
1215 return INVALID_SIZE;
1216 }
1217 size_t l = m_root->Check(ip);
1218 if ( ip.pt->outsizeEnd != ITE() )
1219 {
1220 l = INVALID_SIZE;
1221 }
1222 if ( pGroupStr != NULL )
1223 {
1224 *pGroupStr = ip.pt->ToStrings();
1225 }
1226 return l;
1227 }
1228
1229public:
1230
1232 CRegularExpressionT(void) : m_option(0)
1233 {
1234 }
1235
1243 void SetOption(DWORD dw)
1244 {
1245 m_option = dw;
1246 }
1247
1254 bool SetPattern(const TYP* lpsz)
1255 {
1256 m_RemoveAll();
1258 vw.Add(0);
1259 vw.Add(0); //保険
1260 const WORD* P = vw.ReferBuffer();
1261 CCheckerPtr chk;
1262 if ( ! m_Sub(chk, P, false) )
1263 {
1264 m_RemoveAll();
1265 return false;
1266 }
1267 if ( *P != 0 )
1268 {
1269 m_RemoveAll();
1270 return false;
1271 }
1272 m_root = new CGroupChecker(chk);
1273 m_base = lpsz;
1274 return true;
1275 }
1276
1287 size_t LookingAt(ITE is, ITE ie = ITE(), CVectorT< CStrT<TYP> >* pGroupStr = NULL) const
1288 {
1289 CAbstractChecker::TStaticParam sp;
1290 sp.option = m_option;
1291 CAbstractChecker::TParam ip(is, is, ie, &sp);
1292 return m_MatchSize(ip, pGroupStr);
1293 }
1294
1305 bool Matches(ITE is, ITE ie = ITE(), CVectorT< CStrT<TYP> >* pGroupStr = NULL) const
1306 {
1307 CAbstractChecker::TStaticParam sp;
1308 sp.option = m_option;
1309 CAbstractChecker::TParam ip(is, is, ie, &sp);
1310 size_t l = m_MatchSize(ip, pGroupStr);
1311 if ( l == INVALID_SIZE )
1312 {
1313 return false;
1314 }
1315 ip.StepCur(l);
1316 return ip.IsTerminate();
1317 }
1318
1327 {
1329 size_t foundSize;
1332 };
1333
1342 TFindResult Find(ITE is, ITE ie = ITE(), CVectorT< CStrT<TYP> >* pGroupStr = NULL) const
1343 {
1344 CAbstractChecker::TStaticParam sp;
1345 sp.option = m_option;
1346 CAbstractChecker::TParam ip(is, is, ie, &sp);
1347 TFindResult r;
1348 if ( ! m_root.IsNull() )
1349 {
1350 while ( ! ip.IsTerminate() )
1351 {
1352 ip.top = is;
1353 sp.groupIterators.RemoveAll();
1354 sp.outsizeEnd = ITE();
1355 r.foundSize = m_root->Check(ip);
1356 if ( r.foundSize != INVALID_SIZE )
1357 {
1358 if ( sp.outsizeEnd != ITE() )
1359 {
1360 while ( is != ip.cur )
1361 {
1362 is++;
1363 }
1364 while ( is != sp.outsizeEnd )
1365 {
1366 is++;
1367 r.foundIndex++;
1368 r.foundSize--;
1369 }
1370 }
1371 if ( pGroupStr != NULL )
1372 {
1373 *pGroupStr = ip.pt->ToStrings();
1374 }
1375 return r;
1376 }
1377 if ( sp.outsizeEnd != ITE() )
1378 {
1379 while ( ip.cur != sp.outsizeEnd )
1380 {
1381 r.foundIndex++;
1382 ip.cur++;
1383 }
1384 }
1385 if ( ! ip.IsTerminate() && STRLIB::GetCharSize(*ip.cur) == 2 )
1386 {
1387 r.foundIndex++;
1388 ip.cur++;
1389 }
1390 r.foundIndex++;
1391 ip.cur++;
1392 }
1393 }
1394 r.foundSize = INVALID_SIZE;
1395 r.foundIndex = INVALID_INDEX;
1396 if ( pGroupStr != NULL )
1397 {
1398 *pGroupStr = ip.pt->ToStrings();
1399 }
1400 return r;
1401 }
1402
1423 CVectorT< CStrT<TYP> > Split(ITE is, ITE ie = ITE(), int limit = 0) const
1424 {
1426 while ( limit <= 0 || static_cast<int>(vs.GetSize()) < limit - 1 )
1427 {
1428 TFindResult r = Find(is, ie);
1429 if ( r.foundIndex == INVALID_INDEX )
1430 {
1431 break;
1432 }
1433 CStrT<TYP> s;
1434 loop ( i, r.foundIndex )
1435 {
1436 s += *is++;
1437 }
1438 vs.Add(s);
1439 loop ( i, r.foundSize )
1440 {
1441 is++;
1442 }
1443 }
1444 vs.Add(CStrT<TYP>::FromIterator(is, ie));
1445 if ( limit == 0 )
1446 {
1447 for ( INDEX i = vs.GetSize() - 1; i > 0; i-- )
1448 {
1449 if ( ! vs[i].IsEmpty() )
1450 {
1451 break;
1452 }
1453 vs.Remove(i);
1454 }
1455 }
1456 return vs;
1457 }
1458
1491 {
1492 const CRegularExpressionT* m_pRegEx;
1493 ITE m_is;
1494 ITE m_ie;
1495 CStrT<TYP> m_strDst;
1496 INDEX m_index;
1497 CStrT<TYP> m_foundString;
1498 INDEX m_foundIndex;
1499 CVectorT< CStrT<TYP> > m_foundGroupStr;
1500 public:
1501
1509 CFinder(const CRegularExpressionT* P = NULL, ITE is = ITE(), ITE ie = ITE())
1510 : m_foundIndex(0), m_index(0), m_pRegEx(P), m_is(is), m_ie(ie)
1511 {
1512 Next();
1513 }
1514
1520 bool IsFinding(void) const
1521 {
1522 return m_pRegEx != NULL;
1523 }
1524
1531 bool Next(void)
1532 {
1533 if ( m_pRegEx != NULL )
1534 {
1535 m_strDst += m_foundString;
1536 m_foundString.Empty();
1537 TFindResult r = m_pRegEx->Find(m_is, m_ie, &m_foundGroupStr);
1538 if ( r.foundSize == INVALID_SIZE )
1539 {
1540 m_pRegEx = NULL;
1541 }
1542 else
1543 {
1544 m_strDst += CStrT<TYP>::FromIterator(m_is, m_ie, r.foundIndex);
1545 loop ( i, r.foundIndex ) { m_is++; }
1546 m_foundString = CStrT<TYP>::FromIterator(m_is, m_ie, r.foundSize);
1547 m_foundIndex = m_index + r.foundIndex;
1548 loop ( i, r.foundSize ) { m_is++; }
1549 m_index += r.foundIndex + r.foundSize;
1550 }
1551 }
1552 return m_pRegEx != NULL;
1553 }
1554
1565 bool Replace(const TYP* lpsz)
1566 {
1567 if ( ! IsFinding() ) { return false; }
1568 CStrT<TYP> s;
1569 while ( *lpsz != 0 )
1570 {
1571 if ( STRLIB::GetCharSize(*lpsz) == 2 )
1572 {
1573 s += *lpsz++;
1574 s += *lpsz++;
1575 }
1576 else if ( *lpsz != '\\' )
1577 {
1578 s += *lpsz++;
1579 }
1580 else
1581 {
1582 lpsz++;
1583 TYP c = *lpsz++;
1584 if ( c >= '0' && c <= '9' )
1585 {
1586 INDEX i = c - '0';
1587 if ( m_foundGroupStr.GetSize() > i )
1588 {
1589 s += m_foundGroupStr[i];
1590 }
1591 }
1592 else
1593 {
1594 s += c;
1595 }
1596 }
1597 }
1598 m_foundString = s;
1599 return true;
1600 }
1601
1608 {
1609 return m_foundString;
1610 }
1611
1617 size_t GetFoundSize(void) const
1618 {
1619 return m_foundString.GetLength();
1620 }
1621
1627 {
1628 return m_foundGroupStr;
1629 }
1630
1635 INDEX GetFoundIndex(void) const
1636 {
1637 return m_foundIndex;
1638 }
1639
1647 {
1648 return m_strDst + m_foundString + CStrT<TYP>::FromIterator(m_is, m_ie);
1649 }
1650 };
1651
1658 CFinder GetFinder(ITE is, ITE ie = ITE()) const
1659 {
1660 return CFinder(this, is, ie);
1661 }
1662
1675 CStrT<TYP> ReplaceAll(const TYP* lpsz, ITE is, ITE ie = ITE()) const
1676 {
1677 CFinder f(this, is, ie);
1678 if ( f.IsFinding() )
1679 {
1680 do { f.Replace(lpsz); } while ( f.Next() );
1681 }
1682 return f.GetString();
1683 }
1684
1685private:
1686 friend class CRegularExpressionTest;
1687};
1688
1689
1690
1691}; // TNB
1692
1693
1694
1695//T-TestCaseコードカバレッジEnable
1696#pragma comment(user,"T-Coverage Enable")
1697
1698
1699#if 0
1700
1701正規表現グループと前方参照
1702
1703前方参照を行う正規表現グループには、左から右方向に左丸括弧を数えることによって、
1704番号が付けられます。たとえば、表現 ((A)(B(C))) は、次の 4 つのグループに分類さ
1705れます。
1706
1707 1 ((A)(B(C)))
1708 2 (A)
1709 3 (B(C))
1710 4 (C)
1711グループ 0 は、常に表現全体を表します。
1712
1713
1714http://oraclesqlpuzzle.hp.infoseek.co.jp/regex/
1715
1716
1717
1718#endif
1719
1720
1721#if 0
1722
1723http://programnet.hp.infoseek.co.jp/practical/regex.html
1724郵便番号  \d{3}-\d{4}
1725携帯番号  090-\d{4}-\d{4}
1726電話番号  \d{1,4}?-\d{1,4}?-\d{1,4}
1727生年月日  \d{4}-\d{2}-\d{2}
1728メールアドレス  [!#-9A-~]+@[a-z0-9-_]+\.+[a-z0-9-_]+\.+[a-z0-9-]
1729
1730
1731
1732よくある勘違い その2
1733前述した通り、 ブラケットに囲まれている中ではほとんどのメタキャラ
1734クタはその特殊な意味を失います。 したがって、 [^(foo)]bar という
1735正規表現もまた、「fooではない文字列に続いてbarという文字列が続くもの」
1736 ではありません。「fでもoでも(でも)でもない文字に続いて barという
1737 文字列が続いたもの」 です。 []の内側では、文字列や(より小さな)
1738 正規表現要素をまとめるというカッコの 特別な意味は失われてしまうと
1739 いうことに注意してください。
1740
1741
1742正規表現の確認可能 HP
1743http://lab.moyo.biz/tools/regexp/index.jsp
1744#endif
1745
1746#if 0
1747モード
1748
1749複数行モード * '^''$' が各行の始まりと終わりにマッチするようになります。
1750.が改行にもマッチするモード * '.' が改行文字にもマッチするようにします。
1751大文字と小文字を同一視モード * 大文字と小文字を区別しないようにします。
1752
1753
1754
1755
1756
1757
1758
1759#endif
#define _BIT(X)
BIT演算
Definition: TnbDef.h:307
#define loop(VAR, CNT)
loop構文.
Definition: TnbDef.h:343
文字列情報配列管理関係のヘッダ
ポインタ型ハンドルテンプレート
正規表現ファインダクラス
const CVectorT< CStrT< TYP > > & GetFoundGroupString(void) const
[取得] マッチしたグループ文字列取得.
bool Next(void)
[検索] 次検索
bool Replace(const TYP *lpsz)
[置換] 置き換え.
CStrT< TYP > GetString(void) const
[取得] 置換結果文字列取得.
CStrT< TYP > GetFoundString(void) const
[取得] マッチした文字列取得.
bool IsFinding(void) const
[確認] 検索確認
INDEX GetFoundIndex(void) const
[取得] マッチした位置取得.
CFinder(const CRegularExpressionT *P=NULL, ITE is=ITE(), ITE ie=ITE())
コンストラクタ
size_t GetFoundSize(void) const
[取得] マッチした文字列長取得.
正規表現管理クラステンプレート
bool SetPattern(const TYP *lpsz)
[設定] パターン設定.
CFinder GetFinder(ITE is, ITE ie=ITE()) const
[取得] ファインダー取得.
TFindResult Find(ITE is, ITE ie=ITE(), CVectorT< CStrT< TYP > > *pGroupStr=NULL) const
[検索] 検索
CVectorT< CStrT< TYP > > Split(ITE is, ITE ie=ITE(), int limit=0) const
[取得] 分割.
bool Matches(ITE is, ITE ie=ITE(), CVectorT< CStrT< TYP > > *pGroupStr=NULL) const
[比較] 全体マッチ
CRegularExpressionT(void)
コンストラクタ
CStrT< TYP > ReplaceAll(const TYP *lpsz, ITE is, ITE ie=ITE()) const
[置換] 置き換え.
void SetOption(DWORD dw)
[設定] オプション設定.
@ IGNORECASE
「欧文の大文字と小文字を区別しない」オプション
size_t LookingAt(ITE is, ITE ie=ITE(), CVectorT< CStrT< TYP > > *pGroupStr=NULL) const
[比較] 先頭マッチ
文字列管理テンプレート
Definition: TnbStr.h:74
size_t GetLength(void) const
[取得] 文字列長
Definition: TnbStr.h:518
void Empty(void)
[削除] 空化
Definition: TnbStr.h:197
static CStrT FromIterator(ITE is, ITE ie=ITE(), size_t max=INVALID_SIZE)
[代入] イテレータ代入.
Definition: TnbStr.h:1272
配列型情報管理テンプレート
Definition: TnbVector.h:75
virtual size_t GetSize(void) const
[取得] サイズ取得
Definition: TnbVector.h:368
virtual bool Remove(INDEX index)
[削除] 要素一つ削除.
Definition: TnbVector.h:397
virtual const TYP & At(INDEX index) const
[取得] 要素の参照取得.
Definition: TnbVector.h:233
virtual bool SetSize(size_t size)
[操作] サイズ指定
Definition: TnbVector.h:618
virtual const TYP * ReferBuffer(void) const
[取得] データアドレス取得
Definition: TnbVector.h:664
virtual INDEX Add(const TYP &t)
[追加] 要素一つ追加.
Definition: TnbVector.h:383
int GetCharSize(char c)
[取得] 文字のサイズ(ASCII/SJIS用)
Definition: TnbStrLib.h:341
CWordVector StringToWordVector(LPCSTR lpszAscii)
[変換] ASCII文字列→文字単位配列
Definition: TnbStrVector.h:63
int EscCharToInt(const TYP *&_lpsz)
[変換] エスケープ文字表記変換
Definition: TnbStrLib.h:533
void Swap(T &t1, T &t2)
[変換] スワッパー.
Definition: TnbDef.h:963
TNB Library
Definition: TnbDoxyTitle.txt:2
Find() メソッド用リザルト
bool IsEmpty(void) const
[確認] 要素の有無確認.