IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Détecter le type de chaîne en vue d'un tri avec les expressions régulières


Sujet :

Langage Delphi

  1. #1
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut Détecter le type de chaîne en vue d'un tri avec les expressions régulières
    Amis des expressions régulières, bonjour !

    Moi aussi, je me serais volontiers penché sur l'exercice mais, pour que ce soit amusant, il faudrait un échantillon des chaînes à traiter. Pour les nombres flottants, est-ce qu'on admet la notation scientifique ? Un "currency" dans une chaîne, ça se présente comment ?
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut Déplacement de la discussion et suite
    Je me suis permis de déplacer la suite de cette discussion

    Bonjour,
    je crois que je vais m'y amuser puisque j'ai déjà dégagé quelques expressions, cela me permettra de savoir comment on gère les groupes. Toutefois cela me fait toujours l'impression d'utiliser un marteau pilon.
    le code proposé au départ n'est pas si mal si ce n'est que Currency est privilégié au Float alors que 12345.12 peut aussi bien être l'un que l'autre (nombre de décimales <= à TformatSettings.CurrencyDecimals et pas d'indication de CurrencyString. De plus il faudrait vérifier que l'instruction TryStrToCurr(S1,CurrValue) ne fait pas l'arrondi !

    Pour les nombres flottants, est-ce qu'on admet la notation scientifique ?
    j'avais oublié cette possibilité
    Un "currency" dans une chaîne, ça se présente comment ?
    les formatsettings donnent la réponse sauf si l'on peut jouer avec les devises étrangères
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  3. #3
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut Récupérer le nom du groupe ?
    Re,

    après ces deux heures voici ma tentative Berlin 10.1

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    unit ChercherType;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.RegularExpressions;
     
    type
      TForm8 = class(TForm)
        ATester: TEdit;
        Tester: TButton;
        Resultat: TLabel;
        TesterEntiers: TCheckBox;
        TesterReels: TCheckBox;
        TesterMonnaie: TCheckBox;
        TesterDates: TCheckBox;
        procedure TesterClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure ATesterChange(Sender: TObject);
      private
        { Déclarations privées }
        Expression : String;
        function CreerExpression : String;
      public
        { Déclarations publiques }
      end;
     
    var
      Form8: TForm8;
     
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm8.ATesterChange(Sender: TObject);
    // nouvelle saisie
    begin
    Resultat.Caption:='';
    end;
     
    function TForm8.CreerExpression: String;
    var Entier : String;
        Reel : String;
        Monnaie : String;
        DateExpr : String;
        TestFormat : String;
        aa,mm,jj : word;
    begin
    // groupe entier
    Entier:='(?<Entier>^[+-]?\d+$)';
    // groupe réel
    Reel:='(?<reel>^[+-]?\s?(\d{0,3}\s?['+FormatSettings.ThousandSeparator+']?)(\d{3})?'+FormatSettings.DecimalSeparator+'\d*$)';
    // groupe monnaie
    // uniquement la monnaie des settings
    // selon le format
    TestFormat:=format('%m',[1]);
    if pos(FormatSettings.CurrencyString,TestFormat)=1
      then Monnaie:='(?<Monnaie>^('+FormatSettings.CurrencyString+')?\s?[+-]?\s?(\d{0,3}\s?['+FormatSettings.ThousandSeparator+']?)(\d{3})?'+FormatSettings.DecimalSeparator+'\d{0,'+FormatSettings.CurrencyDecimals.ToString+'}$)'
      else Monnaie:='(?<Monnaie>^[+-]?\s?(\d{0,3}\s?['+FormatSettings.ThousandSeparator+']?)(\d{3})?'+FormatSettings.DecimalSeparator+'\d{0,'+FormatSettings.CurrencyDecimals.ToString+'}\s?('+FormatSettings.CurrencyString+')?$)';
    // groupe date  à améliorer
    // formatSettings.ShortDateFormat
    // jj/mm/aaaa
    DateExpr:='(?<Date>^(0?[1-9]|[12][0-9]|3[01])['+FormatSettings.DateSeparator+'](0?[1-9]|1[012])['+FormatSettings.DateSeparator+']\d{4})$';
     
    if TesterEntiers.Checked then result:=Entier;
    if TesterReels.Checked then
       begin
         if length(Result)>0 then result:=result+'|';
         result:=result+Reel;
       end;
    if TesterMonnaie.Checked then
       begin
         if length(Result)>0 then result:=result+'|';
         result:=result+Monnaie;
       end;
    if TesterDates.Checked then
       begin
         if length(Result)>0 then result:=result+'|';
         result:=result+DateExpr;
       end;
    end;
     
    procedure TForm8.FormCreate(Sender: TObject);
    begin
    Expression:=CreerExpression;
    end;
     
    procedure TForm8.TesterClick(Sender: TObject);
    var Expr : TRegEx;
        Mc : TMatchCollection;
        i : word;
    begin
      Expr:=TRegEx.Create(Expression);
      if Expr.IsMatch(ATester.Text) then
        begin
          // le hic est là , impossible de récupérer le nom du groupe !
          mc:=Expr.Matches(Atester.Text);
          for I := 0 to mc.Count-1 do
           if Mc.Item[i].Success then 
              resultat.caption:=intToStr(i);
        end
      else resultat.Caption:='Chaine';
    end;
     
    end.
    dfm
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    object Form8: TForm8
      Left = 0
      Top = 0
      Caption = 'Type de donn'#233'e saisi'
      ClientHeight = 169
      ClientWidth = 598
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      OnCreate = FormCreate
      PixelsPerInch = 96
      TextHeight = 13
      object Resultat: TLabel
        Left = 64
        Top = 104
        Width = 3
        Height = 13
      end
      object ATester: TEdit
        Left = 64
        Top = 32
        Width = 329
        Height = 21
        TabOrder = 0
        Text = 'ATester'
        OnChange = ATesterChange
      end
      object Tester: TButton
        Left = 64
        Top = 59
        Width = 329
        Height = 25
        Caption = 'Quel type est-ce ?'
        TabOrder = 1
        OnClick = TesterClick
      end
      object TesterEntiers: TCheckBox
        Left = 440
        Top = 24
        Width = 97
        Height = 17
        Caption = 'Tester Entiers'
        Checked = True
        State = cbChecked
        TabOrder = 2
      end
      object TesterReels: TCheckBox
        Left = 440
        Top = 47
        Width = 97
        Height = 17
        Caption = 'Tester R'#233'els'
        Checked = True
        State = cbChecked
        TabOrder = 3
      end
      object TesterMonnaie: TCheckBox
        Left = 440
        Top = 70
        Width = 97
        Height = 17
        Caption = 'Tester Monnaie'
        Checked = True
        State = cbChecked
        TabOrder = 4
      end
      object TesterDates: TCheckBox
        Left = 440
        Top = 93
        Width = 97
        Height = 17
        Caption = 'Tester Dates'
        Checked = True
        State = cbChecked
        TabOrder = 5
      end
    end
    Cependant, impossible de récupérer le nom du groupe (du coup je n'ai pas travailler à fond le format des dates)
    Il y a bien sur la possibilité de passer chaque expression les unes à la suite des autres mais je voulais pouvoir utiliser les groupes pour tout faire en une passe

    N.B. en regardant dans les sources, j'ai l'impression que TryStrToCurr et TryStrToFloat font la même chose, c'est à dire un texttofloat (sauf que le dernier est contrôlé en étendue)
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  4. #4
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    après ces deux heures voici ma tentative Berlin 10.1
    Et moi je viens de passer une heure (sans exagérer) à étudier ton code.

    Il y a des idées intéressantes (notamment l'idée d'utiliser la variable FormatSettings pour composer les expressions) mais la façon dont tu t'y prends est compliquée et je me demande si elle peut fonctionner. Moi en tout cas je n'ai pas réussi.

    Soit dit en passant, je crois (je peux me tromper) que tu fais une confusion entre TMatchCollection et TGroupCollection. On cherche à savoir si une chaîne correspond à une expression : on ne cherche pas plusieurs correspondances dans un texte. C'est donc d'une collection de groupes qu'il s'agit dans ce cas. Et je pense que tu vas rencontrer un problème avec les sous-groupes que tu crées involontairement en utilisant des parenthèses à l'intérieur de tes expressions. Peut-être qu'il faudrait les transformer en groupes non-capturants, avec la syntaxe '(?:'.

    Quoiqu'il en soit, je ne pense qu'on puisse récupérer les noms des groupes : du moins je ne me souviens pas d'avoir vu un exemple qui faisait ça.

    Citation Envoyé par SergioMaster Voir le message
    Il y a bien sûr la possibilité de passer chaque expression les unes à la suite des autres mais je voulais pouvoir utiliser les groupes pour tout faire en une passe
    Personnellement j'aurais adopté la première approche.

    P.-S. Quelque chose dans ce style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    type
      TSortTypeInterne = (
        stiInteger,
        stiCurrency,
        stiNumeric,
        stiDate,
        stiText
      );
     
    function DetectType(const S: string): TSortTypeInterne;
     
      function ExprInteger: string; begin result := '...'; end;
      function ExprCurrency: string; begin result := '...'; end;
      function ExprNumeric: string; begin result := '...'; end;
      function ExprDate: string; begin result := '...'; end;
     
    begin
      if TRegEx.IsMatch(S, ExprInteger) then
        result := stiInteger
      else if TRegEx.IsMatch(S, ExprCurrency) then
        result := stiCurrency
      else if TRegEx.IsMatch(S, ExprNumeric) then
        result := stiNumeric
      else if TRegEx.IsMatch(S, ExprDate) then
        result := stiDate
      else
        result := stiText;
    end;
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  5. #5
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut
    Citation Envoyé par Roland Chastain Voir le message
    Quoiqu'il en soit, je ne pense qu'on puisse récupérer les noms des groupes : du moins je ne me souviens pas d'avoir vu un exemple qui faisait ça.
    moi non plus et c'est bien dommage

    Personnellement j'aurais adopté la première approche.
    oui c'est nettement plus simple, mais je trouvais dommage de ne pouvoir utiliser les alternatives et le nom des groupes et donc ai tenté de les utiliser

    Peut-être qu'il faudrait les transformer en groupes non-capturants, avec la syntaxe '(?:'.
    un truc que je ne connaissais pas , donc une bonne journée pour moi

    Il y a des idées intéressantes (notamment l'idée d'utiliser la variable FormatSettings pour composer les expressions) mais la façon dont tu t'y prends est compliquée
    elle l'est car ce n'était après tout qu'un premier jus à froid (mais sans pression) par contre, les deux premières expressions fonctionne, la troisième (j'en suis moins sûr), la date elle par-contre est à revoir.
    Cependant une vraie expression régulière sur le contrôle des dates est vraiment trop complexe à mon goût, a mon avis un premier contrôle sur la forme suivi d'un tentative de conversion en cas de succès est plus simple. Mon idée était donc de récupérer (toujours dans les formatSettings le shortFormatdate et de le transformer avec un replace des dd, MM et yyyy
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  6. #6
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    un truc que je ne connaissais pas , donc une bonne journée pour moi
    Je ne me plains pas non plus car j'ai appris plus d'une chose en lisant ton code.

    Citation Envoyé par SergioMaster Voir le message
    Cependant une vraie expression régulière sur le contrôle des dates est vraiment trop complexe à mon goût, à mon avis un premier contrôle sur la forme suivi d'un tentative de conversion en cas de succès est plus simple.
    Oui, je crois aussi que ce serait la marche à suivre. Mais du coup est-ce que l'expression régulière sert vraiment à quelque chose ?
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  7. #7
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Euh, chez moi FormatSettings.CurrencyString renvoie "?" et CurrToStr(1) renvoie "1" tout court.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {$APPTYPE CONSOLE}
     
    {$R *.res}
     
    uses
      System.SysUtils;
     
    begin
      try
        with FormatSettings do
        begin
          WriteLn('"', ThousandSeparator, '"');
          WriteLn(DecimalSeparator);
          WriteLn(CurrencyDecimals);
          WriteLn(CurrencyString);
          WriteLn('"', CurrToStr(1), '"');
          WriteLn(Pos(CurrencyString, CurrToStr(1)));
          WriteLn(DateSeparator);
          WriteLn(ShortDateFormat);
        end;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
     
      ReadLn;
    end.
    "*"
    ,
    2
    ?
    "1"
    0
    /
    dd/MM/yyyy
    P.-S. Même le code suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var
      fs: TFormatSettings;
     
    begin
      try
        ...
     
        fs := TFormatSettings.Create;
        fs.CurrencyDecimals := 2;
        fs.CurrencyString := '€';
        fs.CurrencyFormat := 3;
     
        WriteLn('"', CurrToStr(1, fs), '"');
    me renvoie un simple "1".
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  8. #8
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    @SergioMaster

    Je retire ce que j'ai dit : c'est possible de le faire avec une seule expression.

    Voici une petite démonstration, qui est une version simplifiée du code que tu as posté. Pour savoir à quelle sous-expression la chaîne examinée correspond, on exploite le nombre de groupes capturés. C'est un peu empirique, mais ça fonctionne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    {$APPTYPE CONSOLE}
     
    uses
      System.SysUtils, System.Classes, System.RegularExpressions;
     
    function CreerExpression: string;
    var
      Entier: string;
      Reel: string;
      Monnaie: string;
      DateExpr: string;
    begin
      Entier := '(?<Entier>^[+-]?\d+$)';
      Reel := '(?<reel>^[+-]?\s?(\d{0,3}\s?[' + FormatSettings.ThousandSeparator +
        ']?)(\d{3})?' + FormatSettings.DecimalSeparator + '\d*$)';
      Monnaie := '(?<Monnaie>^[+-]?\s?(\d{0,3}\s?[' +
        FormatSettings.ThousandSeparator + ']?)(\d{3})?' +
        FormatSettings.DecimalSeparator + '\d{0,' +
        FormatSettings.CurrencyDecimals.ToString + '}\s?(' +
        FormatSettings.CurrencyString + ')?$)';
      DateExpr := '(?<Date>^(0?[1-9]|[12][0-9]|3[01])[' +
        FormatSettings.DateSeparator + '](0?[1-9]|1[012])[' +
        FormatSettings.DateSeparator + ']\d{4})$';
     
      result := Entier + '|' + Reel + '|' + Monnaie + '|' + DateExpr;
    end;
     
    const
      EXEMPLES: array[0..3] of string = (
        '123',
        '1,5',
        '10 €',
        '04/03/2017'
        );
     
    var
      Expr: TRegEx;
      Match: TMatch;
      i: integer;
     
    begin
      Expr := TRegEx.Create(CreerExpression);
      for i := Low(EXEMPLES) to High(EXEMPLES) do
      begin
        WriteLn('"', EXEMPLES[i], '"');
        Match := Expr.Match(EXEMPLES[i]);
        if Match.Success then
          WriteLn(Match.Groups.Count)
        else
          WriteLn('Aucune correspondance trouvée.');
        WriteLn;
      end;
      ReadLn;
    end.
    "123"
    2

    "1,5"
    4

    "10 ?"
    Aucune correspondance trouvée.

    "04/03/2017"
    12
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  9. #9
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    on exploite le nombre de groupes capturés. C'est un peu empirique, mais ça fonctionne.
    j'y avais pensé mais c'est un peu, comment dire :koi, empirique n'est pas le terme que j'aurais choisi, pas très beau plutôt.

    pour le FormatSettings.CurrencyString renvoie "?" je pense que cela vient du fait que tu utilises une application console dont le page mode n'est pas win1252
    voir la commande chcp 1252 ou chcp 65001 pour de l'UTF8

    Pour ce qui est du CurrToStr voire StrToCurr le hic c'est que cela transforme le nombre mais ne prend pas ne compte le FormatSettings
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if TryStrToCurr('124,54 €',cur) then showmessage('Conversion') else Showmessage('Erreur') ; //>> 'Erreur'
    quant à CurrToCurr qui fait presque la même chose que FloatToStr s'il prend en compte le caractère DecimalSeparator, il ne s'occupe pas de CurrencyString contrairement à Format('%m',[124.54]);
    Note : je m'aperçois que je n'avais pas copié le bon code pour retrouvé la position du symbole monétaire je corrige
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  10. #10
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Bonjour !

    Citation Envoyé par SergioMaster Voir le message
    j'y avais pensé mais c'est un peu, comment dire , empirique n'est pas le terme que j'aurais choisi, pas très beau plutôt.
    Nous sommes d'accord. En fouillant dans mes exemples de code, je me suis aperçu que j'avais déjà étudié ce problème, mais aucune des solutions que j'avais trouvées n'était très belle. J'en conclus que l'opérateur "|" n'est pas approprié dans ce genre de cas où l'on veut distinguer les choses.

    Merci pour tes indications sur le symbole monétaire. Je commence à y voir plus clair.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  11. #11
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut
    Re,
    Je suis à la recherche de la solution idéale, mais comme on dérive un peu du post initial et que le sujet de départ n'incite pas forcément les "amis des expressions régulières" ainsi que "les curieux des expressions régulières" je pense qu'il serait mieux d'ouvrir un nouveaux sujet.
    Je ne l'ai pas encore ouvert parce que je suis en train de modifier mon programme, objectifs :
    - ne pas utiliser les alternatives
    - récupérer la valeur à utiliser pour le tri , j'ai pris en compte ton TSortTypeInterne
    - mes cogitations pour l'instant me pousse quand même à utiliser la notion de Groups.Count pour distinguer le numérique du monétaire (expression avec un seul groupe, la monnaie)
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  12. #12
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Je suis à la recherche de la solution idéale, mais comme on dérive un peu du post initial et que le sujet de départ n'incite pas forcément les "amis des expressions régulières" ainsi que "les curieux des expressions régulières" je pense qu'il serait mieux d'ouvrir un nouveau sujet.
    Oui, d'accord avec toi. Peut-être même déplacer les derniers messages vers une nouvelle discussion ?

    En attendant, voici ma dernière proposition. J'ai retouché tes expressions, en bien ou en mal je ne sais pas : je te laisse regarder.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    {$APPTYPE CONSOLE}
    {$ASSERTIONS ON}
     
    uses
      System.SysUtils, System.RegularExpressions, System.TypInfo;
     
    type
      TSortTypeInterne = (
        stiInteger,
        stiCurrency,
        stiNumeric,
        stiDate,
        stiText
      );
     
    function DetectType(const S: string): TSortTypeInterne;
     
      function ExInt: string;
      begin
        result := '([+-]\s?)?\d+';
      end;
     
      function ExNum: string;
      begin
        with FormatSettings do
          result := Format
          (
            '([+-]\s?)?(\d{1,3}%s?)*\d{1,3}%s\d+',
            [ThousandSeparator, DecimalSeparator]
          );
      end;
     
      function ExCur: string;
      begin
        with FormatSettings do
        begin
          result := Format
          (
            '([+-]\s?)?(\d{1,3}%s?)*\d{1,3}%s\d{1,%d}',
            [ThousandSeparator, DecimalSeparator, CurrencyDecimals]
          );
     
          if Pos(CurrencyString, Format('%m', [1.50])) = 1 then
            result := Format('(%s\s?)?%s', [CurrencyString, result])
          else
            result := Format('%s(\s?%s)?', [result, CurrencyString]);
        end;
      end;
     
      function ExDat: string;
      begin
        with FormatSettings do
          result := Format
          (
            '(0?[1-9]|[12][0-9]|3[01])%s(0?[1-9]|1[012])%s\d{4}',
            [DateSeparator, DateSeparator]
          );
      end;
     
    begin
      if TRegEx.IsMatch(S, '^' + ExInt + '$') then
        result := stiInteger
      else
        if TRegEx.IsMatch(S, '^' + ExNum + '$') then
          result := stiNumeric
        else
          if TRegEx.IsMatch(S, '^' + ExCur + '$') then
            result := stiCurrency
          else
            if TRegEx.IsMatch(S, '^' + ExDat + '$') then
              result := stiDate
            else
              result := stiText;
    end;
     
    procedure Test(const S: string);
    var
      v: TSortTypeInterne;
    begin
      v := DetectType(S);
     
      WriteLn('"', S, '"');
      WriteLn('  ', GetEnumName(TypeInfo(TSortTypeInterne), Ord(v)));
      WriteLn;
    end;
     
    const
      EXEMPLES: array[0..11] of string = (
        '1',
        '+1',
        '+ 1',
     
        '1,5',
        '+1,5',
        '+ 1,5',
     
        '1,50€',
        '1,50 €',
        '1,50 €',
        '11'#160'111,50 €',
        '11'#160'111'#160'111,50 €',
     
        '04/03/2017'
      );
     
    var
      i: integer;
     
    begin
      try
        Assert(FormatSettings.CurrencyString = '€');
        Assert(Format('%m', [1.50]) = '1,50 €');
        Assert(Ord(FormatSettings.ThousandSeparator) = 160);
     
        for i := Low(EXEMPLES) to High(EXEMPLES) do
          Test(EXEMPLES[i]);
      except
        on E: Exception do
          WriteLn(E.ClassName, ': ', E.Message);
      end;
     
      ReadLn;
    end.
    "1"
    stiInteger

    "+1"
    stiInteger

    "+ 1"
    stiInteger

    "1,5"
    stiNumeric

    "+1,5"
    stiNumeric

    "+ 1,5"
    stiNumeric

    "1,50€"
    stiCurrency

    "1,50 €"
    stiCurrency

    "1,50 €"
    stiCurrency

    "11*111,50 €"
    stiCurrency

    "11*111*111,50 €"
    stiCurrency

    "04/03/2017"
    stiDate
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  13. #13
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut
    Citation Envoyé par Roland Chastain Voir le message
    Oui, d'accord avec toi. Peut-être même déplacer les derniers messages vers une nouvelle discussion ?
    ce que je viens de faire

    En attendant, voici ma dernière proposition. J'ai retouché tes expressions, en bien ou en mal je ne sais pas : je te laisse regarder.
    on n'a pas tout à fait la même vision mais presque
    mon expression, encore pas tout à fait au point pour la notation scientifique
    est devenue la suivante ^[+-]?\s?\d{0,3}(\s?\d{3})+,\d*\s?(E[+-]?/d{1,2})?|(?<Monnaie>€)?)$je pensais utiliser une option pour ne capturer que les groupes nommés et ainsi dans une seule fonction déterminer les types : numérique, scientifique et monétaire
    pour ce qui est des dates je n'ai pas retravaillé dessus encore
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  14. #14
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    on n'a pas tout à fait la même vision mais presque
    J'ai édité mon message précédent pour corriger l'expression relative au type stiNumeric.

    Pour la suite de la discussion, personnellement ça m'aiderait d'avoir un échantillon de chaînes commun. Autrement on ne sait pas si on pense vraiment aux mêmes choses. Est-ce que tu pourrais compléter l'échantillon que j'ai déjà proposé, ou en proposer un autre ? J'ai toujours un doute sur ce qui est valable ou pas comme currency. Est-ce que le symbole monétaire est obligatoire ? Je ne suis pas très familier non plus de la notation scientifique. Est-ce qu'elle est autorisée aussi pour le type currency (comme je crois pouvoir le déduire de ton dernier message) ?
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  15. #15
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut
    échantillon possible
    Entiers
    12
    -12
    +12
    // il faudrait aussi voir si ça ne déborde pas
    Numeriques (format français)
    12,12
    -12,12
    +12,12
    12345,124578
    -12345,124578
    +12345,124578
    12 123,12415

    Monétaire (avec ou sans espaces entre le nombre et le symbole quoique normalement il y a un espace)
    -12345,124578 €
    +12345,124578€
    12 123,12415 €

    Scientifique (je découvre moi aussi)
    12E4
    12E-4
    12E+4
    .... ?

    Date (le format court) mais on pourrait aussi travailler sur le format long
    soit dd/mm/yyyy
    29/02/2012
    29/02/2014 << erreur
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  16. #16
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    @SergioMaster

    Merci.

    J'ai un doute sur le type monétaire. Le nombre de chiffres après la virgule ne doit-il pas être deux obligatoirement ? Ça me paraîtrait logique en tout cas. C'est d'ailleurs la valeur de FormatSettings.CurrencyDecimals.

    Pour ce qui est de vérifier le débordement pour le type integer (et aussi, pourquoi pas, pour les autres types), ou la validité d'une date, c'est intéressant mais je dirais que c'est un autre problème.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  17. #17
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Voici donc mon échantillon. Je m'en tiens pour le moment à l'idée qu'une expression monétaire doit avoir deux chiffres après la virgule. J'ai ajouté le cas d'un espace ordinaire employé comme séparateur de milliers. D'ailleurs les séparateurs de milliers ne doivent-ils pas être autorisés aussi pour les nombres entiers ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    const
      EXEMPLES: array[0..20] of string = (
        '1',
        '+1',
        '+ 1',
     
        '1,1',
        '+1,1',
        '+ 1,1',
        '+ 1,111',
        '+ 11 111,111', // avec un espace ordinaire comme séparateur de milliers
        '+ 11'#160'111,111',
        '+ 1,111E1',
        '+ 1,111E+1',
        '+ 1,111E-1',
     
        '1,11€',
        '+1,11€',
        '+ 1,11€',
        '+ 1,11 €',
        '+ 11111,11 €',
        '+ 11 111,11 €',
        '+ 11'#160'111,11 €',
        '+ 11'#160'111'#160'111,11 €',
     
        '11/11/1111'
      );
    Et en pièce jointe la dernière version de mon programme.
    Fichiers attachés Fichiers attachés
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  18. #18
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut
    Citation Envoyé par Roland Chastain Voir le message
    J'ai un doute sur le type monétaire. Le nombre de chiffres après la virgule ne doit-il pas être deux obligatoirement ? Ça me paraîtrait logique en tout cas. C'est d'ailleurs la valeur de FormatSettings.CurrencyDecimals.
    Oui, c'est ce que j'avais en tête la première fois mais j'ai vu que l'on pouvait formater avec plus de décimales Format('%.4m',uncurrency); donc doute

    Pour ce qui est de vérifier le débordement pour le type integer (et aussi, pourquoi pas, pour les autres types), ou la validité d'une date, c'est intéressant mais je dirais que c'est un autre problème.
    oui et non car a) le type entier si débordement est alors un numérique b) pour la date cela me semble primordial pour les autres ça déborde un float ? d'après le source StrToFloat oui à contrario du Currency bizarre

    par contre je plante lamentablement sur l'expression en tenant compte de la notation scientifique je stoppe les frais pour aujourd'hui

    [Edit] j'ai repris
    voilà le dernier jus de mon code (pas totalement propre) pour la partie Numérique, V est prévue pour la future conversion pour le tri

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    function ExprNumeric(const S: String; var V : String): TSortTypeInterne;
       var Expr : TRegEx;
           Match : TMatch;
           Expression,ExpressionM,FormatM,Tstr : String;
           TS,DS : Char;
           i : word;
       begin
        TS:=FormatSettings.ThousandSeparator;
        if Ord(ts)=160 then TStr:='[\s'+TS+']'  // espace insécable (il m'a fait c...r celui là :roll:)
                       else Tstr:=TS;
        DS:=FormatSettings.DecimalSeparator;
        // construction de l'expression
        FormatM:=Format('%.2m',[1.00]);
        if Pos(FormatSettings.CurrencyString,FormatM)=1
        then begin
         Expression:='^(?<Monnaie>(\s'+FormatSettings.CurrencyString+'))?';
         Expression:='(?<Valeur>[+-]?\s?\d{0,3}('+TStr+'?\d{3})?('+DS+'\d*)?)(E[+-]?/d{1,2})?$';
         ExpressionM:='^'+FormatSettings.CurrencyString+'\s.*$';
        end
        else begin
         Expression:='^(?<Valeur>[+-]?(\d{0,3})('+TStr+'?\d{3})*('+DS+'\d*)?)';
         Expression:=Expression+'(?<Sub>(?<Sci>E[+-]?\d{1,2})?';
         Expression:=Expression+'|(?<Monnaie>\s'+FormatSettings.CurrencyString+')?)$';
         ExpressionM:='^.*\s'+FormatSettings.CurrencyString+'$';
      end;
         Expr:=TRegEx.Create(Expression,[roExplicitCapture]);
         Match:=Expr.Match(S);
         if Match.Success
         then begin
             V:= Match.Groups.Item['Valeur'].Value;
             result := stiNumeric;
              if TRegEx.IsMatch(V,ExpressionM)
                then begin
                  result:=stiCurrency;
                end;
                if TRegEx.IsMatch(S,'^.*E\d{1,2}$')
                then begin
                  V:=Match.Groups[0].Value;
                  result:=stiScience;
                end;
         end
         else begin
            result:=stiText;
            V:=S;
         end;
        end;
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  19. #19
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    j'ai repris mon bâton de pèlerin pour traiter les dates format court ou long
    j'ai usé (et abusé) des expressions régulières, mais c'était bien le but
    Voilà où j'en suis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     function ExprDate(const S: String; var V : String): TSortTypeInterne;
       var Expr : TRegEx;
           Match : TMatch;
           Expression,AString : String;
           Formats,Mois : TStringList;
           ADate : TDateTime;
       begin
          Formats := TStringList.Create;
          Mois:=TStringList.Create;
          try
            Formats.Add(Format('^%s$',[FormatSettings.ShortDateFormat]));
            Formats.Add(Format('^%s$',[FormatSettings.LongDateFormat]));
            Formats.Text:=TRegEx.Replace(Formats.Text,' ','\s'); // espace
            Formats.Text:=TRegEx.Replace(Formats.Text,'\xA0','[\s\xA0]'); // insécable
            Formats.Text:=TRegEx.Replace(Formats.Text,'dddd','.*\s?');
            Formats.Text:=TRegEx.Replace(Formats.Text,'dd','(0?[0-9]|[1-3]?[0-9])');
            Formats.Text:=TRegEx.Replace(Formats.Text,'d','(0?[0-9]|[1-3]?[0-9])');
            Formats.Text:=TRegEx.Replace(Formats.Text,'yyyy','(\d{2}|\d{4})');
     
            mois.Duplicates:=dupIgnore;
            mois.Sorted:=true;
           // les noms de mois court
            for AString in FormatSettings.ShortMonthNames do
                 Mois.Add(Format('%s',[TRegEx.Replace(AString,'\.','\.')]));
           // les noms de mois longs
            for AString in FormatSettings.LongMonthNames do
                Mois.Add(Format('%s',[AString]));
            Mois.Delimiter:='|';
            Formats.Text:=TRegEx.Replace(Formats.Text,'MMMM',Mois.DelimitedText);
            Formats.Text:=TRegEx.Replace(Formats.Text,'MM','(0?[1-9]|[1][0-2])');
            Formats.Delimiter:='|';
            Formats.QuoteChar:=#0;
            Expression:=Formats.DelimitedText;
            Memo1.Lines.Add(Expression);
            Expr:=TRegEx.Create(Expression,[roIgnoreCase]);
            Match:=Expr.Match(S);
            V:=S;
            result:=stiText;
            if Match.Success then
              begin
                 try
                   ADate:=VartoDateTime(V);
                   V:=DateToStr(ADate);
                   result:=stiDate;
                 except
     
                 end;
              end;
          finally
            Mois.Free;
            Formats.Free;
          end;
       end;
    ce n'est pas parfait dans le sens où je ne réussi pas encore à traiter le nom du jour (s'il existe).
    En construisant l'expression avec les deux formats et des groupes nommés je me suis heurté à une erreur de nom de groupe dupliqué il faut donc que j'investigue d'avantage

    en faisant en deux passes ( format court, format long) le problème de se poserait pas bien sûr
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  20. #20
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 030
    Points : 40 928
    Points
    40 928
    Billets dans le blog
    62
    Par défaut fin (présumée) de cogitation sur les dates
    Voici la fonction pour le traitement des dates (sans toutefois tester le jour littéral et ce dernier par rapport à la date saisie pour un contrôle parfait)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
     function ExprDate(const S: String; var V : String): TSortTypeInterne;
       var Expr : TRegEx;
           Match : TMatch;
           Expression,AString : String;
           Mois : TStringList;
           ADate : TDateTime;
           aa,mm,jj : word;
       function ParseFormat (const F : String) : String;
         begin
            Result:=F;
            Result:=TRegEx.Replace(Result,'dddd ','(?<NomJour>.*\s)?');
            Result:=TRegEx.Replace(result,' ','\s'); // espace
            Result:=TRegEx.Replace(Result,'\xA0','[\s\xA0]'); // insécable
            Result:=TRegEx.Replace(Result,'dd','d');
            Result:=TRegEx.Replace(Result,'d','(?<Jour>0?[0-9]|[1-3]?[0-9])');
            Result:=TRegEx.Replace(Result,'yyyy','(?<Annee>\d{2}?\d{2})');
            Result:=TRegEx.Replace(Result,'MMMM','(?<NomMois>'+Mois.DelimitedText+')');
            Result:=TRegEx.Replace(Result,'MM','(?<Mois>0?[1-9]|[1][0-2])');
         end;
        function NumeroMois (const MMMM : String) : integer;
        var i : integer;
        begin
          result:=-1;
          for i := Low(FormatSettings.LongMonthNames) to High(FormatSettings.LongMonthNames)
           do begin
             if SameText(MMMM,FormatSettings.LongMonthNames[i]) then
               begin
                 Result:=i;
                 Break;
               end;
           end;
           if result=-1 then
           begin
           for i := Low(FormatSettings.ShortMonthNames) to High(FormatSettings.ShortMonthNames)
            do begin
             if SameText(MMMM,FormatSettings.LongMonthNames[i]) then
               begin
                 Result:=i;
                 Break;
               end;
            end;
     
           end;
     
        end;
       begin
          Mois:=TStringList.Create;
          try
            mois.Duplicates:=dupIgnore;
            mois.Sorted:=true;
           // les noms de mois court
            for AString in FormatSettings.ShortMonthNames do
                 Mois.Add(Format('%s',[TRegEx.Replace(AString,'\.','\.')]));
           // les noms de mois longs
            for AString in FormatSettings.LongMonthNames do
                Mois.Add(Format('%s',[AString]));
            Mois.Delimiter:='|';
            // passe format court
            Expression:=ParseFormat(FormatSettings.ShortDateFormat);
            Expr:=TRegEx.Create(Expression,[roExplicitCapture,roIgnoreCase]);
            Match:=Expr.Match(S);
            if Match.Success AND TryStrToDate(S,ADate) then
              begin
                V:=DateToStr(StrToDate(S));
                result:=stiDate;
              end
            else begin
               V:=S;
               result:=stiText;
            end;
            // passe format long
            if result=stiText then
             begin
              Expression:=ParseFormat(FormatSettings.LongDateFormat);
              memo1.Lines.Add(Expression);
              Expr:=TRegEx.Create(Expression,[roExplicitCapture,roIgnoreCase]);
              Match:=Expr.Match(S);
              if Match.Success then
               begin
                 try
                   ADate:=VartoDateTime(V);
                   V:=DateToStr(ADate);
                   result:=stiDate;
                 except
                   // jour
                    jj:=StrToIntDef(Match.Groups['Jour'].Value,0);
                   // mois
                   mm:=NumeroMois(Match.Groups['NomMois'].Value);
                   // an
                   aa:=StrToIntDef(Match.Groups['Annee'].Value,0);
                   memo1.lines.add(Match.Groups.Count.ToString);
                   try
                    ADate:=EncodeDate(aa,mm,jj);
                    result:=stiDate;
                    V:=DateToStr(ADate);
                   except
                     result:=stiText;
                     V:=S;
                   end;
                 end;
              end;
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

Discussions similaires

  1. [Free Pascal] Validateur de chaîne FEN utilisant les expressions régulières
    Par Roland Chastain dans le forum Codes sources à télécharger
    Réponses: 0
    Dernier message: 03/10/2014, 10h40
  2. Validation d'une chaîne FEN par les expressions régulières
    Par Roland Chastain dans le forum Delphi
    Réponses: 10
    Dernier message: 01/10/2014, 20h27
  3. Réponses: 3
    Dernier message: 28/07/2014, 01h48
  4. Recherche de chaîne avec une expression régulière complexe
    Par mdriesbach dans le forum Général Python
    Réponses: 4
    Dernier message: 28/07/2009, 22h46
  5. [FAQ] Comment tester une chaîne de caractères avec une expression régulière ?
    Par Baptiste Wicht dans le forum Vos Contributions VBScript
    Réponses: 1
    Dernier message: 20/11/2007, 19h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo