![]() |
RegEx Frage
Hallo,
Ich möchte folgende Textzeile:
Code:
mittels RegEx parsen.
0 @Reference@ Objekt
Dazu verwende ich folgendes Pattern:
Code:
Das funktioniert auch Tip Top, nur würde ich gern beim zweiten Match "(@[^@]+@ |)", dass nur der Inhalt zwischen den @-Zeichen gematcht wird. Inwiefern muss ich das Pattern abändern?
^(0|[1-9]+[0-9]*) (@[^@]+@ |)([A-Za-z0-9_]+)( [^\n\r]*|)$
Herzliche Grüße |
AW: RegEx Frage
Noch paar Klammern
SQL-Code:
/
(@([^@]+)@ |)
SQL-Code:
, (Klammern um das, was man haben will :roll:)
@([^@]+)@ |
oder ein paar Look-Around ![]() |
AW: RegEx Frage
Zitat:
Ich vergas zu erwähnen, dass der von @ eingeschlossene Wert optional ist! Deswegen wird das nichts, indem ich das @ einfach vor und hinter die Klammer setze. |
AW: RegEx Frage
Zitat:
Code:
(oder sowas in der Art).
(@([^@]+)?@ |)
MfG Dalai |
AW: RegEx Frage
Einmal wüst gebastelt:
Code:
Im Prinzip außenrum eine non-Capturing group für die @s, innen drin ein Look-Ahead/Look-Behind
^(0|[1-9][\d]*) (?:@?((?<=@)[^@]+(?=@)|)(?:@ )?)([\w]+)( [^\n\r]*|)$
Code:
verhindert dann auch noch
^(0|[1-9][\d]*) (?:@?((?<=@)[^@]+(?=@)|(?!@))(?:@ )?)([\w]+)( [^\n\r]*|)$
Code:
Durch das
0 @@ Objekt
Code:
wird übrigens auch
[^\n\r]*
Code:
gematcht.
0 Referenz Objekt
|
AW: RegEx Frage
Code:
@SProske: Prima, das macht genau das, was es soll. Vielen lieben Dank Dir und den anderen Beitragenden dafür ;)
^(0|[1-9][\d]*) (?:@?((?<=@)[^@]+(?=@)|(?!@))(?:@ )?)([\w]+)( [^\n\r]*|)$
|
AW: RegEx Frage
Hallo,
Eine kleine Frage als Nachtrag: wie muss ich das Pattern abändern, sodass Objekt nach einer Fallentscheidung geparst wird? Wenn Objekt von @-Zeichen umgeben wird, soll es nur den Inhalt, also ohne @-Zeichen Matchen, ansonsten immer den kompletten Inhalt. Beste Grüße |
AW: RegEx Frage
Könntest du dafür mal ein Beispiel geben, wie der String aussehen sollte und was du in welcher Gruppe matchen willst?
|
AW: RegEx Frage
Zitat:
Also mein bisheriges patter schaut so aus:
Code:
Beispiele für ein Match sind:
(0|[1-9][\d]*) (?:@?((?<=@)[^@]+(?=@)|(?!@))(?:@ )?)([A-Za-z0-9_]+)( [^\n\r]*|)
Zitat:
Zitat:
Zitat:
Beispiel: Zitat:
|
AW: RegEx Frage
Hast du Möglichkeit, das ganze nachzubearbeiten?
Also einfach die @s wegzudoktorn, wenn in der Gruppe davor eines der Signalwörter auftritt? Das sollte wesentlich einfacher gehen, als das Regex so anzupassen, dass die Signalwörter berücksichtigt werden und dann eine Fallunterscheidung zu machen. Was sollte denn passieren bei:
Code:
1 NAME @Max /Mustermann/@
1 FAMC I123 1 FAMC @I123 1 FAMC I123@ 1 FAMC @I@12@3@ |
AW: RegEx Frage
Zitat:
|
AW: RegEx Frage
So langsam wird es kompliziert :)
Probier mal:
Code:
Im Prinzip prüfe ich, ob es einen deiner Specialfälle gibt, dann wird der gematcht - sonst das normale Verfahren. Und das nochmal für den Inhalt. Leider erzeugt Delphi im Match-Objekt einige eigentlich nicht vorhandene Gruppen - ich wüsste auch nicht wie ich die wegkriege. Deswegen mal zur Auswertung ein kleines Konsolenprogramm.
(0|[1-9][\d]*)\h+(?:@?((?<=@)[^@]+(?=@)|(?!@))(?:@\h+)?)(?<Special>FAM[SC]|CHIL)?(?(Special)|(?<NoSpecial>\w+))(?(Special)\h+@([^\v]*|)@|\h*([^\v]*|))
Zum selber durchgucken: ![]()
Delphi-Quellcode:
program Project1;
{$APPTYPE CONSOLE} uses System.SysUtils, RegularExpressions; const Sample = '0 @Reference@ Objekt' + sLineBreak + '1 NAME Max /Mustermann/' + sLineBreak + '2 DATE 22 APR 2016' + sLineBreak + '1 FAMC @I123@' + sLineBreak + '1 FAMS @I124@' + sLineBreak + '1 CHIL @I125@'; var Match: TMatch; begin try Match := TRegEx.Match(Sample, '(0|[1-9][\d]*)\h+(?:@?((?<=@)[^@]+(?=@)|(?!@))(?:@\h+)?)(?<Special>FAM[SC]|CHIL)?(?(Special)|(?<NoSpecial>\w+))(?(Special)\h+@([^\v]*|)@|\h*([^\v]*|))'); while Match.Success do begin if Match.Groups.Count = 7 then begin WriteLn('Number:' + Match.Groups[1].Value); WriteLn('Reference:' + Match.Groups[2].Value); WriteLn('Object:' + Match.Groups[4].Value); WriteLn('Content:' + Match.Groups[6].Value); end else if Match.Groups.Count = 6 then begin WriteLn('Number:' + Match.Groups[1].Value); WriteLn('Reference:' + Match.Groups[2].Value); WriteLn('Object:' + Match.Groups[3].Value); WriteLn('Content:' + Match.Groups[5].Value); end else WriteLn('Das ist anders :(:' + Match.Groups[0].Value); WriteLn(''); Match := Match.NextMatch; end; ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. |
AW: RegEx Frage
Wow, danke! Wenn es nicht kompliziert wäre, hätte ich die Frage eh nicht ins Forum geworfen ;)
Im Prinzip erfüllt das Pattern ja seine Sache :D Also nochmal zum Aufbau:
Code:
Level = Zahl 0-99
Level (Reference) Tag (Value)
Reference = von @-Zeichen umschlossener Wert Tag = einzelnes Wort, wobei die Wörter FAMC FAMS und CHIL eine Auswirkung auf Value, die dann ebenfalls von @-Zeichen umgeben ist haben Value = Rest der Zeile, abhängig vom Tag Die eingeklammerten Werte sind optional, ABER ich hätte gern immer genau 4 Match-SubStrings, also auch NIL Matches sind erlaubt. Das macht es einfacher für mich die Daten weiterzuverarbeiten. Das Pattern
Code:
hat aber bis zu 6 Match-SubStrings
(?x)
(0|[1-9][\d]*)\h+ (?:@?((?<=@)[^@]+(?=@)|(?!@))(?:@\h+)?) (?<Special>FAM[SC]|CHIL)? (?(Special)|(?<NoSpecial>\w+)) (?(Special)\h+@([^\v]*|)@|\h*([^\v]*|)) Also sollte folgendes rauskommen:
Code:
1 = Level
2 = (Reference) 3 = Tag (Special/NoSpecial) 4 = Value |
AW: RegEx Frage
Wenn du einen Parser für eine Zeile schreiben würdest, hättest du zuverlässigere Ergebnisse und wärst wohl schon fertig. :stupid:
Hier mal so ein Parser mit der ![]()
Delphi-Quellcode:
unit Unit2;
interface uses System.SysUtils, stateless; type TRow = record public Level : Integer; Reference: string; Tag : string; Value : string; RefValue : string; public class function Parse( const AStr: string ): TRow; static; function ToString( ): string; end; implementation uses System.StrUtils; class function TRow.Parse( const AStr: string ): TRow; type {$SCOPEDENUMS ON} TParserState = ( Level, ReferenceOrTag, Reference, TagStart, Tag, ValueOrRefValue, Value, RefValue, Finished, Error ); TParseerTrigger = ( ParseChar, ParseFinish ); {$SCOPEDENUMS OFF} TRowParserSM = TStateMachine<TParserState, TParseerTrigger>; var sm : TRowParserSM; pc : TRowParserSM.TTriggerWithParameters<Char>; buffer : string; c : Char; res : TRow; errorTransition: TRowParserSM.TTransition; begin buffer := ''; sm := TRowParserSM.Create( TParserState.Level ); try pc := sm.SetTriggerParameters<Char>( TParseerTrigger.ParseChar ); {$REGION 'Configuration'} { Level } sm.Configure( TParserState.Level ) {} .OnEntryFrom<Char>( pc, procedure( const c: Char; const t: TRowParserSM.TTransition ) begin if t.IsReentry then buffer := buffer + c; end ) {} .OnExit( procedure( const t: TRowParserSM.TTransition ) begin if not t.IsReentry then begin res.Level := StrToInt( buffer ); buffer := ''; end; end ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Error ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of '0' .. '9': Result := TParserState.Level; ' ': begin if buffer.IsEmpty then Result := TParserState.Error else begin Result := TParserState.ReferenceOrTag; end; end; else Result := TParserState.Error; end; end ); { ReferenceOrTag } sm.Configure( TParserState.ReferenceOrTag ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Error ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of '@': Result := TParserState.Reference; ' ': Result := TParserState.ReferenceOrTag; 'A' .. 'Z': Result := TParserState.Tag; else Result := TParserState.Error; end; end ); { Reference } sm.Configure( TParserState.Reference ) {} .OnEntryFrom<Char>( pc, procedure( const c: Char; const t: TRowParserSM.TTransition ) begin if t.IsReentry then buffer := buffer + c; end ) {} .OnExit( procedure( const t: TRowParserSM.TTransition ) begin if not t.IsReentry then begin res.Reference := buffer; buffer := ''; end; end ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Error ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of '@': if buffer.IsEmpty then Result := TParserState.Error else Result := TParserState.TagStart; else Result := TParserState.Reference; end; end ); { TagStart } sm.Configure( TParserState.TagStart ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Error ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of ' ': Result := TParserState.TagStart; 'A' .. 'Z': Result := TParserState.Tag; else Result := TParserState.Error; end; end ); { Tag } sm.Configure( TParserState.Tag ) {} .OnEntryFrom<Char>( pc, procedure( const c: Char ) begin buffer := buffer + c; end ) {} .OnExit( procedure( const t: TRowParserSM.TTransition ) begin if not t.IsReentry then begin res.Tag := buffer; buffer := ''; end; end ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Finished ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of 'A' .. 'Z': if buffer.Length >= 4 then Result := TParserState.Error else Result := TParserState.Tag; ' ': Result := TParserState.ValueOrRefValue; else Result := TParserState.Error; end; end ); { ValueOrRefValue } sm.Configure( TParserState.ValueOrRefValue ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Finished ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of '@': Result := TParserState.RefValue; ' ': Result := TParserState.ValueOrRefValue; else Result := TParserState.Value; end; end ); { Value } sm.Configure( TParserState.Value ) {} .OnEntryFrom<Char>( pc, procedure( const c: Char; const t: TRowParserSM.TTransition ) begin buffer := buffer + c; end ) {} .OnExit( procedure( const t: TRowParserSM.TTransition ) begin if not t.IsReentry then begin res.Value := buffer; buffer := ''; end; end ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Finished ) {} .PermitReentry( TParseerTrigger.ParseChar ); { RefValue } sm.Configure( TParserState.RefValue ) {} .OnEntryFrom<Char>( pc, procedure( const c: Char; const t: TRowParserSM.TTransition ) begin if t.IsReentry then buffer := buffer + c; end ) {} .OnExit( procedure( const t: TRowParserSM.TTransition ) begin if not t.IsReentry then begin res.RefValue := buffer; buffer := ''; end; end ) {} .Permit( TParseerTrigger.ParseFinish, TParserState.Error ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of '@': if buffer.IsEmpty then Result := TParserState.Error else Result := TParserState.Finished; else Result := TParserState.RefValue; end; end ); { Finished } sm.Configure( TParserState.Finished ) {} .PermitReentry( TParseerTrigger.ParseFinish ) {} .PermitDynamic<Char>( pc, function( const c: Char ): TParserState begin case c of ' ': Result := TParserState.Finished; else Result := TParserState.Error; end; end ); { Error } sm.Configure( TParserState.Error ) {} .OnEntry( procedure( const t: TRowParserSM.TTransition ) begin errorTransition := t; end ); {$ENDREGION} { Parse the string } for c in AStr do begin if not sm.CanFire( TParseerTrigger.ParseChar ) then break; sm.Fire<Char>( pc, c ); end; { Fire Finish Trigger } if sm.CanFire( TParseerTrigger.ParseFinish ) then sm.Fire( TParseerTrigger.ParseFinish ); { Check the final state } if sm.State <> TParserState.Finished then raise Exception.Create( errorTransition.ToString ); Result := res; finally sm.Free; end; end; function TRow.ToString: string; begin Result := Level.ToString( ) {} + IfThen( Reference.IsEmpty, '', ' @' + Reference + '@' ) {} + ' ' + Tag.ToUpperInvariant( ) {} + IfThen( Value.IsEmpty, '', ' ' + Value ) {} + IfThen( RefValue.IsEmpty, '', ' @' + RefValue + '@' ); end; end. |
AW: RegEx Frage
So, ich greife das Thema erneut auf. Ich habe nun ein wunderbar funktionierendes RegEx-Pattern:
Code:
Nun gibt es drei Ausnahmen, die ich gern integrieren würde. Sie betreffen die Teil-Abschnitte
(0|[1-9][\d]*) (?:@?((?<=@)[^@]+(?=@)|(?!@))(?:@ )?)([A-Za-z0-9_]+)( [^\n\r]*|)
Code:
und
([A-Za-z0-9_]+)
Code:
. Wenn
( [^\n\r]*|)
Code:
<> NOTE, CONT oder CONC ist, soll
([A-Za-z0-9_]+)
Code:
getrimmt werden, sonst nicht. Wie würde das aussehen? Ich kenne mich mit Konditionalen Ausdrücken leider gar nicht aus.
( [^\n\r]*|)
Vielen Dank im Voraus |
AW: RegEx Frage
Was meinst du mit "soll getrimmt werden"?
Prinzipiell kannst du die drei Sonderfälle NOTE, CONT oder CONC behandeln, in dem du etwas auf die Art:
Code:
machst - das würde zwar auch den String "NOTENormalfall" parsen, ich glaube allerdings auf Grund der Angaben, das das Problem in deinem Fall nicht relevant ist.
(((NOTE|CONT|CONC)Sonderfall)|(([A-Za-z0-9_]+)Normalfall))
|
AW: RegEx Frage
Also, es geht darum, dass bei den drei genannten Fällen, das gematchte Ergebnis nicht getrimmt werden soll, in allen anderen Fällen schon. Ich meine also, dass alle Leerzeichen vor und nach dem Match automatisch entfernt werden. Ist das mittels RegEx möglich? Das würde mir erheblich Rechenzeit Sören, dennbisher prüfe ich dann jedes Match und führe ggf. die interne String-Trimfunktion aus. Das kostet Zeit, vor allem bei sehr langen Strings.
|
AW: RegEx Frage
Naja, prinzipiell kannst du es so machen, wie ich eben beschrieben habe. Also eine Alternative zwischen "Sonderfall" und "Normalfall", wobei du im Normalfall trimmst und in den Sonderfällen nicht. Klar ist, dass du dann das Ergebnis in zwei verschiedenen Variablen erhältst, und je nachdem die eine oder die andere Variable verwenden musst. Ob aber diese Vorgangsweise insgesamt schneller ist als ein nachträgliches Trim, halte ich für sehr fraglich, die Rechenzeit für die Regex-Auswertung steigt möglicherweise stärker an als um die Zeit, die ein Trim kostet.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:43 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz