Wie drucke ich einen erweiterten regulären Ausdruck in nicht erweiterter Form?

8

Ist es möglich , einen regulären Ausdruck drucken erweiterte Notation erstellt ( qr/.../x) in nicht expandierter Form? Zum Beispiel:

my $decimal = qr/
  (?=\d|\.\d)  # look-ahead to ensure at least one of the optional parts matches
  \d*          # optional whole digits
  (?:\.\d*)?   # optional decimal point and fractional digits
/x;

say $decimal;

Ich möchte, dass dies als gedruckt wird (?=\d|\.\d)\d*(?:\.\d*)?.

Ich könnte einen Parser schreiben, um die nicht funktionierenden Teile zu entfernen, aber das würde das replizieren, was Perl bereits tut, und ich würde wahrscheinlich einige der nicht trivialen Fälle falsch verstehen.

(Ja, das scheint ein bisschen albern zu sein. Ich habe einen Anwendungsfall, in dem ich viele Nachrichten wie drucken muss, matched <pattern>und ich möchte Nachrichten auf eine einzelne Zeile beschränken, während die erweiterte Notation für Muster verwendet werden kann.)

Michael Carman
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Samuel Liew

Antworten:

7

Perl bietet kein solches Dienstprogramm. Es analysiert Regex-Muster; es erzeugt sie nicht. Die Zeichenfolge des Objekts ist die genaue Zeichenfolge, die dem Parser bereitgestellt wird und in eine Zeichenfolge eingeschlossen ist, die (?:...)die Flags berücksichtigt. Die dem Parser bereitgestellte Zeichenfolge ist das Post-Interpolations-Literal abzüglich der Trennzeichen. [1]

Dies wäre jedoch mit einem Regex-Parser trivial.

Es gibt YAPE :: Regex , aber es wurde schon lange nicht mehr aktualisiert. Zum Beispiel unterstützt es nicht die (?^:...)in der Stringifizierung von Regex in der modernen Version von Perl gefundene.

Es gibt auch Regexp :: Parser . Es ist neuer, aber es unterstützt auch nicht (?^:...)! Aber wenn wir das umgehen würden, wäre es perfekt, da Leerzeichen und Kommentare natürlich ignoriert werden! Alles, was wir tun müssen, ist das Muster zu analysieren und eine Zeichenfolge aus dem Analysebaum zu erhalten.

Schließlich gibt es Regexp :: Parsertron . Es ist das neueste und unterstützt zwar (?^:...), unterscheidet jedoch keine Leerzeichen und Kommentare von Token mit "exakten Übereinstimmungen".

Verwenden wir also Regexp :: Parser. [2]

#!/usr/bin/perl
use strict;
use warnings;
use feature qw( say );

use Regexp::Parser qw( );

{
   @ARGV == 1
      or die("usage\n");

   my $re = $ARGV[0];

   # R::P doesn't support «(?^:...)», so we'll
   # provide a backwards-compatible stringification.
   $re =~ s{^\(\?\^(\w*):}{
      my %on = map { $_ => 1 } split //, $1;
      my $on  = join "", grep  $on{$_}, qw( i m s x );
      my $off = join "", grep !$on{$_}, qw( i m s x );
      "(?$on-$off:"
   }e;

   my $parser = Regexp::Parser->new($re);
   my $roots = $parser->root
      or die($parser->errmsg);

   say join "", map $_->visual, @$roots;
}

Prüfung:

$ despace_re '(?^x:
   (?=\d|\.\d)  # look-ahead to ensure at least one of the optional parts matches
   \d*          # optional whole digits
   (?:\.\d*)?   # optional decimal point and fractional digits
)'
(?x-ims:(?=\d|\.\d)\d*(?:\.\d*)?)

  1. \Q, \uUnd ähnliche sind in der gleichen Stufe bei Interpolation. \N{...}wird aufgelöst, \N{U+...}um die aktuellen Einstellungen für Zeichennamen zu verewigen. Andere Fluchten wie \x27, \x{0000027}, \\und \/werden Zeichen für Zeichen erhalten.

  2. Eine auf YAPE :: Regex basierende Lösung wurde in einer früheren Überarbeitung dieser Antwort verwendet.

Ikegami
quelle
1
Fügen Sie Ihren Fund hinzu mit re::regex_pattern($qr)? Das tut ihnen einen Weg geben zu bekommen , was sie brauchen, oder in der Nähe , dass, vielleicht mit einem einfachen Unter
zdim
@zdim, ich sehe nicht, wie überhaupt re::regex_pattern($qr)hilft.
Ikegami
Es entfernt das umgebende Zeug ( (?: )) ... das ist etwas. Die Leerzeichen sind dornig, wie ich merke - wenn es xMod gibt, kann es immer noch legale Leerzeichen geben [ ](ein Beispiel, an das ich mich erinnern könnte, es gibt wahrscheinlich mehr) ... aber sie könnten Zeilenumbrüche manuell entfernen? Dann gäbe es einen akzeptablen Ausdruck?
zdim
@zdim, aber das Zeug zu entfernen ist eine schlechte Sache. Es könnte das Muster ändern, um etwas anderes zu bedeuten. Es ist da, weil es ein wesentlicher Teil des Musters ist.
Ikegami
@zdim, vier Fälle , in denen Leerzeichen signifikant sind bei der Verwendung von /x: \␠, [␠], (?-x:␠)und (?-x)␠. Es könnte mehr geben.
Ikegami