Я сделал несколько незначительных изменений в скрипте perl, который нашел в perlmonks (для получения значений из командной строки) и сохранил его как re_pl2el.pl
(приведено ниже). Затем следующее делает достойную работу по преобразованию PCRE в регулярные выражения elisp, по крайней мере для неэкзотических случаев, которые я тестировал.
(defun pcre-to-elre (regex)
(interactive "MPCRE expression: ")
(shell-command-to-string (concat "re_pl2el.pl -i -n "
(shell-quote-argument regex))))
(pcre-to-elre "__\\w: \\d+") ;-> "__[[:word:]]: [[:digit:]]+"
Он не обрабатывает несколько «угловых» случаев, таких как застенчивые {N,M}?
конструкции perl, и, конечно, не выполнение кода и т. Д., Но он может служить вашим потребностям или послужить хорошей отправной точкой для такого. Поскольку вам нравится PCRE, я предполагаю, что вы знаете достаточно perl, чтобы исправить любые случаи, которые вы часто используете. Если нет, дайте мне знать, и мы, возможно, сможем их исправить.
Я был бы счастлив с помощью сценария, который анализировал бы регулярное выражение в AST, а затем выплевывал его обратно в формате elisp (с тех пор он мог выплевывать его и в формате rx
), но я не мог найти ничего, что могло бы сделать это и казалось большой работой, когда я должен был работать над диссертацией. :-) Мне трудно поверить, что никто этого не сделал.
Ниже моя "улучшенная" версия re_pl2el.pl. -i
означает, что не удваивать escape для строк, а -n
означает, что не печатать последний перевод строки.
#! /usr/bin/perl
#
# File: re_pl2el.pl
# Modified from http://perlmonks.org/?node_id=796020
#
# Description:
#
use strict;
use warnings;
# version 0.4
# TODO
# * wrap converter to function
# * testsuite
#--- flags
my $flag_interactive; # true => no extra escaping of backslashes
if ( int(@ARGV) >= 1 and $ARGV[0] eq '-i' ) {
$flag_interactive = 1;
shift @ARGV;
}
if ( int(@ARGV) >= 1 and $ARGV[0] eq '-n' ) {
shift @ARGV;
} else {
$\="\n";
}
if ( int(@ARGV) < 1 ) {
print "usage: $0 [-i] [-n] REGEX";
exit;
}
my $RE='\w*(a|b|c)\d\(';
$RE='\d{2,3}';
$RE='"(.*?)"';
$RE="\0".'\"\t(.*?)"';
$RE=$ARGV[0];
# print "Perlcode:\t $RE";
#--- encode all \0 chars as escape sequence
$RE=~s#\0#\\0#g;
#--- substitute pairs of backslashes with \0
$RE=~s#\\\\#\0#g;
#--- hide escape sequences of \t,\n,... with
# corresponding ascii code
my %ascii=(
t =>"\t",
n=> "\n"
);
my $kascii=join "|",keys %ascii;
$RE=~s#\\($kascii)#$ascii{$1}#g;
#--- normalize needless escaping
# e.g. from /\"/ to /"/, since it's no difference in perl
# but might confuse elisp
$RE=~s#\\"#"#g;
#--- toggle escaping of 'backslash constructs'
my $bsc='(){}|';
$RE=~s#[$bsc]#\\$&#g; # escape them once
$RE=~s#\\\\##g; # and erase double-escaping
#--- replace character classes
my %charclass=(
w => 'word' , # TODO: emacs22 already knows \w ???
d => 'digit',
s => 'space'
);
my $kc=join "|",keys %charclass;
$RE=~s#\\($kc)#[[:$charclass{$1}:]]#g;
#--- unhide pairs of backslashes
$RE=~s#\0#\\\\#g;
#--- escaping for elisp string
unless ($flag_interactive){
$RE=~s#\\#\\\\#g; # ... backslashes
$RE=~s#"#\\"#g; # ... quotes
}
#--- unhide escape sequences of \t,\n,...
my %rascii= reverse %ascii;
my $vascii=join "|",keys %rascii;
$RE=~s#($vascii)#\\$rascii{$1}#g;
# print "Elispcode:\t $RE";
print "$RE";
#TODO whats the elisp syntax for \0 ???