001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.commons.lang;
020
021
022
023/**
024        Der CFMLString ist eine Hilfe fuer die Transformer, 
025        er repraesentiert den CFML Code und bietet Methoden an, 
026        um alle noetigen Informationen auszulesen und Manipulationen durchzufuehren. 
027        Dies um, innerhalb des Transformer, wiederkehrende Zeichenketten-Manipulationen zu abstrahieren.
028 *
029 */
030public final class ParserString {
031
032        /**
033         * Mindestens einen Space
034         */
035        public static final short AT_LEAST_ONE_SPACE=0;
036        
037        /**
038         * Mindestens ein Space
039         */
040        public static final short ZERO_OR_MORE_SPACE=1;
041        
042
043        public static final char CHAR_DOLLAR=(char)36;
044        public static final char CHAR_POUND=(char)163;
045        public static final char CHAR_EURO=(char)8364;
046        
047        /**
048         * Field <code>pos</code>
049         */
050        protected int pos=0;
051        /**
052         * Field <code>text</code>
053         */
054        protected char[] text;
055        /**
056         * Field <code>lcText</code>
057         */
058        protected char[] lcText;
059        
060        
061        /**
062         * Diesen Konstruktor kann er CFML Code als Zeichenkette uebergeben werden.
063         * @param text CFML Code
064         */
065        public ParserString(String text) {
066                init(text);
067        }
068        
069        /**
070         * Gemeinsame Initialmethode der drei Konstruktoren, diese erhaelt den CFML Code als 
071         * char[] und uebertraegt ihn, in die interen Datenhaltung. 
072         * @param str
073         */
074        protected void init(String str) {
075                int len=str.length();
076                text=new char[len];
077                lcText=new char[len];
078
079                for(int i=0;i<len;i++) {
080                        char c=str.charAt(i);
081                        text[i]=c;
082                        if(c=='\n' || c=='\r' || c=='\t') {
083                                lcText[i]=' ';
084                        }
085                        else lcText[i]=((c>='a' && c<='z') || (c>='0' && c<='9'))?c:Character.toLowerCase(c);
086                }
087        }
088
089        /**
090         * Gibt zurueck ob, 
091         * ausgehend von der aktuellen Position des internen Zeigers im Text,
092         * noch ein Zeichen vorangestellt ist.
093         * @return boolean Existiert ein weieters Zeichen nach dem Zeiger.
094         */
095        public boolean hasNext()  {
096                return pos+1<text.length;
097        }
098        public boolean hasNextNext()  {
099                return pos+2<text.length;
100        }
101
102        public boolean hasPrevious()  {
103                return pos-1>=0;
104        }
105        public boolean hasPreviousPrevious()  {
106                return pos-2>=0;
107        }
108
109        /**
110         * Stellt den internen Zeiger auf die naechste Position. 
111         * Ueberlappungen ausserhalb des Index des Textes werden ignoriert.
112        */
113        public void next(){
114                pos++;
115        }
116        /**
117         * Stellt den internen Zeiger auf die vorhergehnde Position. 
118         * Ueberlappungen ausserhalb des Index des Textes werden ignoriert.
119         */
120        public void previous(){
121                pos--;
122        }
123
124        /**
125         * Gibt das Zeichen (Character) an der aktuellen Position des Zeigers aus.
126         * @return char Das Zeichen auf dem der Zeiger steht.
127         */
128        public char getCurrent() {
129                return text[pos];
130        }
131
132        /**
133         * Gibt das Zeichen (Character) an der naechsten Position des Zeigers aus.
134         * @return char Das Zeichen auf dem der Zeiger steht plus 1.
135         */
136        public char getNext() {
137                return text[pos+1];
138        }
139        
140        /**
141         * Gibt das Zeichen, als Kleinbuchstaben, an der aktuellen Position des Zeigers aus.
142         * @return char Das Zeichen auf dem der Zeiger steht als Kleinbuchstaben.
143         */
144        public char getCurrentLower() {
145                return lcText[pos];
146        }
147        
148        /**
149         * Gibt das Zeichen, als Grossbuchstaben, an der aktuellen Position des Zeigers aus.
150         * @return char Das Zeichen auf dem der Zeiger steht als Grossbuchstaben.
151         */
152        public char getCurrentUpper() {
153                return Character.toUpperCase(text[pos]);
154        }
155        
156        /**
157         * Gibt das Zeichen, als Kleinbuchstaben, an der naechsten Position des Zeigers aus.
158         * @return char Das Zeichen auf dem der Zeiger steht plus 1 als Kleinbuchstaben.
159         */
160        public char getNextLower() {
161                return lcText[pos];
162        }
163
164        /**
165         * Gibt das Zeichen an der angegebenen Position zurueck.
166         * @param pos Position des auszugebenen Zeichen.
167         * @return char Das Zeichen an der angegebenen Position.
168         */
169        public char charAt(int pos) {
170                return text[pos];
171        }
172        
173        /**
174         * Gibt das Zeichen, als Kleinbuchstaben, an der angegebenen Position zurueck.
175         * @param pos Position des auszugebenen Zeichen.
176         * @return char Das Zeichen an der angegebenen Position als Kleinbuchstaben.
177         */
178        public char charAtLower(int pos) {
179                return lcText[pos];
180        }
181
182        /**
183         * Gibt zurueck ob das naechste Zeichen das selbe ist wie das Eingegebene.
184         * @param c Zeichen zum Vergleich.
185         * @return boolean 
186         */
187        public boolean isNext(char c) {
188                if(!hasNext()) return false;
189                return lcText[pos+1]==c;
190        }
191        
192        public boolean isPrevious(char c) {
193                if(!hasPrevious()) return false;
194                return lcText[pos-1]==c;
195        }
196
197        /**
198         * Gibt zurueck ob das naechste Zeichen das selbe ist wie das Eingegebene.
199         * @param c Zeichen zum Vergleich.
200         * @return boolean 
201         */
202        public boolean isCurrentIgnoreSpace(char c) {
203                if(!hasNext()) return false;
204                int start=getPos();
205                removeSpace();
206                
207                boolean is=isCurrent(c);
208                setPos(start);
209                return is;
210        }
211
212        /**
213         * Gibt zurueck ob das naechste Zeichen das selbe ist wie das Eingegebene.
214         * @param c Zeichen zum Vergleich.
215         * @return boolean 
216         */
217        public boolean isCurrentIgnoreSpace(String str) {
218                if(!hasNext()) return false;
219                int start=getPos();
220                removeSpace();
221                
222                boolean is=isCurrent(str);
223                setPos(start);
224                return is;
225        }
226        
227        /**
228         * Gibt zurueck ob das aktuelle Zeichen zwischen den Angegebenen liegt.
229         * @param left Linker (unterer) Wert.
230         * @param right Rechter (oberer) Wert.
231         * @return Gibt zurueck ob das aktuelle Zeichen zwischen den Angegebenen liegt.
232         */
233        public boolean isCurrentBetween(char left, char right) {
234                if(!isValidIndex()) return false;
235                return lcText[pos]>=left && lcText[pos]<=right;
236        }
237        
238        /**
239         * Gibt zurueck ob das aktuelle Zeichen eine Zahl ist.
240         * @return Gibt zurueck ob das aktuelle Zeichen eine Zahl ist.
241         */
242        public boolean isCurrentDigit() {
243                if(!isValidIndex()) return false;
244                return (lcText[pos]>='0' && lcText[pos]<='9');
245        }
246        
247        /**
248         * Gibt zurueck ob das aktuelle Zeichen eine Zahl ist.
249         * @return Gibt zurueck ob das aktuelle Zeichen eine Zahl ist.
250         */
251        public boolean isCurrentQuoter() {
252                if(!isValidIndex()) return false;
253                return lcText[pos]=='"' || lcText[pos]=='\'';
254        }
255        
256        /**
257         * Gibt zurueck ob das aktuelle Zeichen ein Buchstabe ist.
258         * @return Gibt zurueck ob das aktuelle Zeichen ein Buchstabe ist.
259         */
260        public boolean isCurrentLetter() {
261                if(!isValidIndex()) return false;
262                return lcText[pos]>='a' && lcText[pos]<='z';
263        }
264        public boolean isCurrentNumber() {
265                if(!isValidIndex()) return false;
266                return lcText[pos]>='0' && lcText[pos]<='9';
267        }
268        
269        public boolean isCurrentWhiteSpace() {
270                if(!isValidIndex()) return false;
271                return (lcText[pos]==' ' || lcText[pos]=='\t' || lcText[pos]=='\b' || lcText[pos]=='\r' || lcText[pos]=='\n');
272                // return lcText[pos]>='a' && lcText[pos]<='z';
273        }
274        
275        public boolean forwardIfCurrentWhiteSpace() {
276                boolean rtn=false;
277                while(isCurrentWhiteSpace()) {
278                        pos++;
279                        rtn=true;
280                } 
281                return rtn;
282        }
283        
284        public boolean isNextWhiteSpace() {
285                if(!hasNext()) return false;
286                return (lcText[pos+1]==' ' || lcText[pos+1]=='\t' || lcText[pos+1]=='\b' || lcText[pos+1]=='\r' || lcText[pos+1]=='\n');
287        }
288        
289        public boolean isNextNextWhiteSpace() {
290                if(!hasNextNext()) return false;
291                return (lcText[pos+2]==' ' || lcText[pos+2]=='\t' || lcText[pos+2]=='\b' || lcText[pos+2]=='\r' || lcText[pos+2]=='\n');
292        }
293        
294        public boolean isPreviousWhiteSpace() {
295                if(!hasPrevious()) return false;
296                return (lcText[pos-1]==' ' || lcText[pos-1]=='\t' || lcText[pos-1]=='\b' || lcText[pos-1]=='\r' || lcText[pos-1]=='\n');
297        }
298        
299        public boolean isPreviousPreviousWhiteSpace() {
300                if(!hasPreviousPrevious()) return false;
301                return (lcText[pos-2]==' ' || lcText[pos-2]=='\t' || lcText[pos-2]=='\b' || lcText[pos-2]=='\r' || lcText[pos-2]=='\n');
302        }
303        
304    /**
305     * Gibt zurueck ob das aktuelle Zeichen ein Special Buchstabe ist.
306     * @return Gibt zurueck ob das aktuelle Zeichen ein Buchstabe ist.
307     */
308        public boolean isCurrentSpecial() {
309        if(!isValidIndex()) return false;
310        return lcText[pos]=='_' || lcText[pos]==CHAR_DOLLAR || lcText[pos]==CHAR_EURO || lcText[pos]==CHAR_POUND;
311    }
312        
313        /**
314         * Gibt zurueck ob das aktuelle Zeichen das selbe ist wie das Eingegebene.
315         * @param c char Zeichen zum Vergleich.
316         * @return boolean
317         */
318        public boolean isCurrent(char c) {
319                if(!isValidIndex()) return false;
320                return lcText[pos]==c;
321        }
322
323        public boolean isLast(char c) {
324                if(lcText.length==0) return false;
325                return lcText[lcText.length-1]==c;
326        }
327        
328        /**
329         * Stellt den Zeiger eins nach vorn, wenn das aktuelle Zeichen das selbe ist wie das Eingegebene, 
330         * gibt zurueck ob es das selbe Zeichen war oder nicht.
331         * @param c char Zeichen zum Vergleich.
332         * @return boolean
333         */
334        public boolean forwardIfCurrent(char c) {
335                if(isCurrent(c)) {
336                        pos++;
337                        return true;
338                } 
339                return false;
340        }
341        
342        /**
343         * Gibt zurueck ob das aktuelle und die folgenden Zeichen die selben sind,
344         * wie in der angegebenen Zeichenkette.
345         * @param str String Zeichen zum Vergleich.
346         * @return boolean
347         */
348        public boolean isCurrent(String str) {
349                if(pos+str.length()>text.length) return false;
350                for(int i=str.length()-1;i>=0;i--)   {
351                        if(str.charAt(i)!=lcText[pos+i]) return false;
352                }
353                return true;    
354        }
355        
356        /**
357         * Gibt zurueck ob das aktuelle und die folgenden Zeichen die selben sind, 
358         * wie in der angegebenen Zeichenkette, 
359         * wenn ja wird der Zeiger um die Laenge des String nach vorne gesetzt.
360         * @param str String Zeichen zum Vergleich.
361         * @return boolean
362         */
363        public boolean forwardIfCurrent(String str) {
364                boolean is=isCurrent(str);
365                if(is)pos+=str.length();
366                return is;
367        }
368        
369
370        
371
372        public boolean forwardIfCurrent(String str, boolean startWithSpace) {
373                if(!startWithSpace) return forwardIfCurrent(str);
374                
375                int start=pos;
376                if(!removeSpace())return false;
377                
378                if(!forwardIfCurrent(str)){
379                        pos=start;
380                        return false;
381                }
382                return true;
383        }
384
385        
386        public boolean forwardIfCurrent(String first,String second,String third, boolean startWithSpace) {
387                if(!startWithSpace) return forwardIfCurrent(first, second, third);
388                int start=pos;
389                
390                if(!removeSpace())return false;
391                
392                if(!forwardIfCurrent(first,second,third)){
393                        pos=start;
394                        return false;
395                }
396                return true;    
397        }
398        
399
400        /**
401         * Gibt zurueck ob das aktuelle und die folgenden Zeichen die selben sind gefolgt nicht von einem word character, 
402         * wenn ja wird der Zeiger um die Laenge des String nach vorne gesetzt.
403         * @param str String Zeichen zum Vergleich.
404         * @return boolean
405         */
406        public boolean forwardIfCurrentAndNoWordAfter(String str) {
407                int c=pos;
408                if(forwardIfCurrent(str)) {
409                        if(!isCurrentLetter() && !isCurrent('_'))return true;
410                }
411                pos=c;
412                return false;
413        }
414        public boolean forwardIfCurrentAndNoWordNumberAfter(String str) {
415                int c=pos;
416                if(forwardIfCurrent(str)) {
417                        if(!isCurrentLetter() && !isCurrentLetter() && !isCurrent('_'))return true;
418                }
419                pos=c;
420                return false;
421        }
422        
423        /**
424         * Gibt zurueck ob first den folgenden Zeichen entspricht, gefolgt von Leerzeichen und second.
425         * @param first Erste Zeichen zum Vergleich (Vor den Leerzeichen).
426         * @param second Zweite Zeichen zum Vergleich (Nach den Leerzeichen).
427         * @return Gibt zurueck ob die eingegebenen Werte dem Inhalt beim aktuellen Stand des Zeigers entsprechen.
428         */
429        public boolean isCurrent(String first,char second) {
430                int start=pos;
431                if(!forwardIfCurrent(first)) return false; 
432                removeSpace();
433                boolean rtn=isCurrent(second); 
434                pos=start;
435                return rtn;                     
436        }
437        
438        /**
439         * Gibt zurueck ob first den folgenden Zeichen entspricht, gefolgt von Leerzeichen und second.
440         * @param first Erstes Zeichen zum Vergleich (Vor den Leerzeichen).
441         * @param second Zweites Zeichen zum Vergleich (Nach den Leerzeichen).
442         * @return Gibt zurueck ob die eingegebenen Werte dem Inhalt beim aktuellen Stand des Zeigers entsprechen.
443         */
444        public boolean isCurrent(char first,char second) {
445                int start=pos;
446                if(!forwardIfCurrent(first)) return false; 
447                removeSpace();
448                boolean rtn=isCurrent(second); 
449                pos=start;
450                return rtn;                     
451        }
452        
453        /**
454         * Gibt zurueck ob first den folgenden Zeichen entspricht, 
455         * gefolgt von Leerzeichen und second,
456         * wenn ja wird der Zeiger um die Laenge der Uebereinstimmung nach vorne gestellt.
457         * @param first Erste Zeichen zum Vergleich (Vor den Leerzeichen).
458         * @param second Zweite Zeichen zum Vergleich (Nach den Leerzeichen).
459         * @return Gibt zurueck ob der Zeiger vorwaerts geschoben wurde oder nicht.
460         */
461        public boolean forwardIfCurrent(String first,char second) {
462                int start=pos;
463                if(!forwardIfCurrent(first)) return false; 
464                removeSpace();
465                boolean rtn=forwardIfCurrent(second); 
466                if(!rtn)pos=start;
467                return rtn;     
468        }
469        
470        /**
471         * Gibt zurueck ob ein Wert folgt und vor und hinterher Leerzeichen folgen.
472         * @param before Definition der Leerzeichen vorher.
473         * @param val Gefolgter Wert der erartet wird.
474         * @param after Definition der Leerzeichen nach dem Wert.
475         * @return Gibt zurueck ob der Zeiger vorwaerts geschoben wurde oder nicht.
476         */
477        public boolean forwardIfCurrent(short before, String val,short after) {
478                int start=pos;
479                // space before
480                if(before==AT_LEAST_ONE_SPACE) {
481                        if(!removeSpace()) return false;
482                }
483                else removeSpace();
484                
485                // value
486                if(!forwardIfCurrent(val)) {
487                        setPos(start);
488                        return false;
489                }
490                
491                // space after
492                if(after==AT_LEAST_ONE_SPACE) {
493                        if(!removeSpace()) { 
494                                setPos(start);
495                                return false; 
496                        } 
497                }
498                else removeSpace();
499                return true;
500        }
501        
502        /**
503         * Gibt zurueck ob first den folgenden Zeichen entspricht, 
504         * gefolgt von Leerzeichen und second,
505         * wenn ja wird der Zeiger um die Laenge der Uebereinstimmung nach vorne gestellt.
506         * @param first Erste Zeichen zum Vergleich (Vor den Leerzeichen).
507         * @param second Zweite Zeichen zum Vergleich (Nach den Leerzeichen).
508         * @return Gibt zurueck ob der Zeiger vorwaerts geschoben wurde oder nicht.
509         */
510        public boolean forwardIfCurrent(char first,char second) {
511                int start=pos;
512                if(!forwardIfCurrent(first)) return false; 
513                removeSpace();
514                boolean rtn=forwardIfCurrent(second); 
515                if(!rtn)pos=start;
516                return rtn;     
517        }
518        
519        /**
520         * Gibt zurueck ob first den folgenden Zeichen entspricht, gefolgt von Leerzeichen und second.
521         * @param first Erste Zeichen zum Vergleich (Vor den Leerzeichen).
522         * @param second Zweite Zeichen zum Vergleich (Nach den Leerzeichen).
523         * @return Gibt zurueck ob die eingegebenen Werte dem Inhalt beim aktuellen Stand des Zeigers entsprechen.
524         */
525        public boolean isCurrent(String first,String second) {
526                int start=pos;
527                if(!forwardIfCurrent(first)) return false; 
528                removeSpace();
529                boolean rtn=isCurrent(second); 
530                pos=start;
531                return rtn;                     
532        }
533        
534        /**
535         * Gibt zurueck ob first den folgenden Zeichen entspricht, 
536         * gefolgt von Leerzeichen und second,
537         * wenn ja wird der Zeiger um die Laenge der Uebereinstimmung nach vorne gestellt.
538         * @param first Erste Zeichen zum Vergleich (Vor den Leerzeichen).
539         * @param second Zweite Zeichen zum Vergleich (Nach den Leerzeichen).
540         * @return Gibt zurueck ob der Zeiger vorwaerts geschoben wurde oder nicht.
541         */
542        public boolean forwardIfCurrent(String first,String second) {
543                int start=pos;
544                
545                if(!forwardIfCurrent(first)) return false; 
546                
547                if(!removeSpace()){
548                        pos=start;
549                        return false;
550                }
551                boolean rtn=forwardIfCurrent(second); 
552                if(!rtn)pos=start;
553                return rtn;     
554        }
555        
556        public boolean forwardIfCurrent(String first,String second,String third) {
557                int start=pos;
558                if(!forwardIfCurrent(first)) return false; 
559                
560                if(!removeSpace()){
561                        pos=start;
562                        return false;
563                }
564                
565                if(!forwardIfCurrent(second)){
566                        pos=start;
567                        return false;
568                }
569                
570                if(!removeSpace()){
571                        pos=start;
572                        return false;
573                }
574                
575                boolean rtn=forwardIfCurrent(third); 
576                if(!rtn)pos=start;
577                return rtn;     
578        }
579        
580        public boolean forwardIfCurrent(String first,String second,String third, String forth) {
581                int start=pos;
582                if(!forwardIfCurrent(first)) return false; 
583                
584                if(!removeSpace()){
585                        pos=start;
586                        return false;
587                }
588                
589                if(!forwardIfCurrent(second)){
590                        pos=start;
591                        return false;
592                }
593                
594                if(!removeSpace()){
595                        pos=start;
596                        return false;
597                }
598                
599                
600                if(!forwardIfCurrent(third)){
601                        pos=start;
602                        return false;
603                }
604                
605                if(!removeSpace()){
606                        pos=start;
607                        return false;
608                }
609                
610                boolean rtn=forwardIfCurrent(forth); 
611                if(!rtn)pos=start;
612                return rtn;     
613                
614        }
615        
616        
617        
618        /**
619         * Gibt zurueck ob sich vor dem aktuellen Zeichen Leerzeichen befinden.
620         * @return Gibt zurueck ob sich vor dem aktuellen Zeichen Leerzeichen befinden.
621         */
622        public boolean hasSpaceBefore() {
623                return pos > 0 && lcText[pos - 1] == ' ';
624        }
625        
626        /**
627         * Stellt den Zeiger nach vorne, wenn er sich innerhalb von Leerzeichen befindet, 
628         * bis die Leerzeichen fertig sind. 
629         * @return Gibt zurueck ob der Zeiger innerhalb von Leerzeichen war oder nicht.
630         */
631        public boolean removeSpace() {
632                int start=pos;
633                while(pos<text.length && lcText[pos]==' ') {
634                        pos++;
635                }
636                return (start<pos);
637        }
638        
639        /**
640         * Stellt den internen Zeiger an den Anfang der naechsten Zeile, 
641         * gibt zurueck ob eine weitere Zeile existiert oder ob es bereits die letzte Zeile war.
642         * @return Existiert eine weitere Zeile.
643         */
644        public boolean nextLine() {
645                while(isValidIndex() && text[pos]!='\n') {
646                        next();
647                }
648                if(isValidIndex() && text[pos]=='\n') {
649                        next();
650                        return isValidIndex();
651                }
652                return false;
653        }
654        
655        /**
656         * Gibt eine Untermenge des CFMLString als Zeichenkette zurueck, 
657         * ausgehend von start bis zum Ende des CFMLString.
658         * @param start Von wo aus die Untermege ausgegeben werden soll.
659         * @return Untermenge als Zeichenkette
660         */
661        public String substring(int start) {
662                return substring(start,text.length-start);
663        }
664
665        /**
666         * Gibt eine Untermenge des CFMLString als Zeichenkette zurueck, 
667         * ausgehend von start mit einer maximalen Laenge count.
668         * @param start Von wo aus die Untermenge ausgegeben werden soll.
669         * @param count Wie lange die zurueckgegebene Zeichenkette maximal sein darf.
670         * @return Untermenge als Zeichenkette.
671         */
672        public String substring(int start, int count) {
673                return String.valueOf(text,start,count);
674        }
675
676        /**
677         * Gibt eine Untermenge des CFMLString als Zeichenkette in Kleinbuchstaben zurueck, 
678         * ausgehend von start bis zum Ende des CFMLString.
679         * @param start Von wo aus die Untermenge ausgegeben werden soll.
680         * @return  Untermenge als Zeichenkette in Kleinbuchstaben.
681         */
682        public String substringLower(int start) {
683                return substringLower(start,text.length-start);
684        }
685
686        /**
687         * Gibt eine Untermenge des CFMLString als Zeichenkette in Kleinbuchstaben zurueck, 
688         * ausgehend von start mit einer maximalen Laenge count.
689         * @param start Von wo aus die Untermenge ausgegeben werden soll.
690         * @param count Wie lange die zurueckgegebene Zeichenkette maximal sein darf.
691         * @return  Untermenge als Zeichenkette in Kleinbuchstaben.
692         */
693        public String substringLower(int start, int count) {
694                return String.valueOf(lcText,start,count);
695        }
696        
697        /**
698         * Gibt eine Untermenge des CFMLString als CFMLString zurueck, 
699         * ausgehend von start bis zum Ende des CFMLString.
700         * @param start Von wo aus die Untermenge ausgegeben werden soll.
701         * @return Untermenge als CFMLString
702         */
703        public ParserString subCFMLString(int start) {
704                return subCFMLString(start,text.length-start);
705        }
706        
707        /**
708        * Gibt eine Untermenge des CFMLString als CFMLString zurueck, 
709        * ausgehend von start mit einer maximalen Laenge count.
710        * @param start Von wo aus die Untermenge ausgegeben werden soll.
711        * @param count Wie lange die zurueckgegebene Zeichenkette maximal sein darf.
712        * @return Untermenge als CFMLString
713        */
714   public ParserString subCFMLString(int start, int count) {
715                return new ParserString(String.valueOf(text,start,count));
716                /*
717                 NICE die untermenge direkter ermiiteln, das problem hierbei sind die lines
718                
719                int endPos=start+count;
720                int LineFrom=-1;
721                int LineTo=-1;
722                for(int i=0;i<lines.length;i++) {
723                        if()
724                }
725        
726                return new CFMLString(
727                0, 
728                String.valueOf(text,start,count).toCharArray(), 
729                String.valueOf(lcText,start,count).toCharArray(), 
730                lines);
731                */
732   }
733        
734        @Override
735        public String toString() {
736                return new String(this.text);
737        }
738        
739        /**
740         * Gibt die aktuelle Position des Zeigers innerhalb des CFMLString zurueck.
741         * @return Position des Zeigers
742         */
743        public int getPos() {
744                return pos;
745        }
746        
747        /**
748         * Setzt die Position des Zeigers innerhalb des CFMLString, ein ungueltiger index wird ignoriert.
749          * @param pos Position an die der Zeiger gestellt werde soll.
750         */
751        public void setPos(int pos) {
752                this.pos= pos;
753        }
754
755        /**
756         * Gibt zurueck ob der Zeiger auf dem letzten Zeichen steht.
757         * @return Gibt zurueck ob der Zeiger auf dem letzten Zeichen steht.
758         */
759        public boolean isLast() {
760                return pos==text.length-1;
761        }
762        
763        /**
764         * Gibt zurueck ob der Zeiger nach dem letzten Zeichen steht.
765         * @return Gibt zurueck ob der Zeiger nach dem letzten Zeichen steht.
766         */
767        public boolean isAfterLast() {
768                return pos>=text.length;
769        }
770        /**
771         * Gibt zurueck ob der Zeiger einen korrekten Index hat.
772         * @return Gibt zurueck ob der Zeiger einen korrekten Index hat.
773         */
774        public boolean isValidIndex() {
775                return pos<text.length;
776        }
777        
778        /**
779         * Gibt zurueck, ausgehend von der aktuellen Position, 
780         * wann das naechste Zeichen folgt das gleich ist wie die Eingabe, 
781         * falls keines folgt wird -1 zurueck gegeben. 
782         * Gross- und Kleinschreibung der Zeichen werden igoriert.
783         * @param c gesuchtes Zeichen
784         * @return Zeichen das gesucht werden soll.
785         */
786        public int indexOfNext(char c) {
787                for(int i=pos;i<lcText.length;i++) {
788                        if(lcText[i]==c) return i;
789                }
790                return -1;
791        }
792        
793        /**
794         * Gibt das letzte Wort das sich vor dem aktuellen Zeigerstand befindet zurueck, 
795         * falls keines existiert wird null zurueck gegeben.
796         * @return Word vor dem aktuellen Zeigerstand.
797         */
798        public String lastWord() {
799                int size = 1;
800                while (pos - size > 0 && lcText[pos - size] == ' ') {
801                        size++;
802                }
803                while (pos - size > 0
804                        && lcText[pos - size] != ' '
805                        && lcText[pos - size] != ';') {
806                        size++;
807                }
808                return this.substring((pos - size + 1), (pos - 1));
809        }
810
811        /**
812         * Gibt die Laenge des CFMLString zurueck.
813         * @return Laenge des CFMLString.
814         */
815        public int length() {
816                return text.length;
817        }
818
819        /**
820         * Prueft ob das uebergebene Objekt diesem Objekt entspricht.
821         * @param o Object zum vergleichen.
822         * @return Ist das uebergebene Objekt das selbe wie dieses.
823         */
824        public boolean equals(Object o) {
825                if(!(o instanceof ParserString))return false;
826                return o.toString().equals(this.toString());
827        }
828
829}