我承认喜欢PCRE正则表达式比使用emacs要好得多,如果没有其他原因,当我输入'('我几乎总是想要一个分组运算符。当然,\ w和类似的东西比其他等价物更方便。
但是,当然希望改变emacs的内部结构会很疯狂。但我认为应该可以从PCRE表达式转换为emacs表达式,并进行所有需要的转换,以便我可以写:
(defun my-super-regexp-function ...
(search-forward (pcre-convert "__\\w: \d+")))
(或类似)。
任何人都知道可以执行此操作的elisp库吗?
编辑:从以下答案中选择回复...
哇,我喜欢从4天假期回来,找到一系列有趣的答案!我喜欢这两种解决方案的工作。最后,看起来exec-a-script和直接elisp版本的解决方案都可以工作,但从纯粹的速度和“正确性”方法来看,elisp版本肯定是人们更喜欢的版本(我自己包括)。
答案 0 :(得分:23)
https://github.com/joddie/pcre2el是此答案的最新版本。
pcre2el
或rxt
(RegeXp Translator或RegeXp Tools)是一个用于在Emacs中处理正则表达式的实用程序,它基于regexp语法的递归下降解析器。除了将(一部分)PCRE语法转换为其Emacs等效语言之外,它还可以执行以下操作:
- 将Emacs语法转换为PCRE
- 将语法转换为
rx
,一种基于S表达式的regexp语法- 通过以
rx
形式显示解析树并突出显示相应的代码块来解开复杂的正则表达式- 显示与正则表达式匹配的字符串(产品)的完整列表,前提是列表是有限的
- 提供regexp语法的实时字体锁定(目前仅适用于Elisp缓冲区 - TODO列表中的其他模式)
原始答案的文字如下......
这是一个quick and ugly Emacs lisp solution(编辑:现在更永久地定位here)。它主要基于pcrepattern
手册页中的描述,并按令牌工作,只转换以下结构:
( .. )
|
{M,N}
\Q .. \E
\a
,\c
,\e
,\f
,\n
,\r
,\t
,{ {1}}和\x
+八进制数字\
,\d
,\D
,\h
,\H
,\s
,\S
,{{ 1}} \v
和\V
保持原样(使用Emacs自己的单词和非单词字符的想法)对于更复杂的PCRE断言它没有做任何事情,但它确实试图在字符类中转换转义。对于包含类似\w
之类的字符类的情况,这可以通过转换为具有交替的非捕获组来完成。
它通过了我为它编写的测试,但肯定存在错误,并且逐个令牌扫描的方法可能很慢。换句话说,没有保修。但也许它会为某些目的做足够多的工作。欢迎有兴趣的人士改进; - )
\W
答案 1 :(得分:8)
我对perl脚本做了一些小修改,我发现on 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:]]+"
它没有像perl的害羞{N,M}?
构造那样处理一些“角落”案例,当然也没有代码执行等等,但它可能满足您的需求或者是一个良好的起点。因为你喜欢PCRE我认为你知道足够的perl来修复你经常使用的任何情况。如果不让我知道,我们可以解决它们。
我会更乐意使用一个脚本将正则表达式解析为AST,然后以elisp格式将其吐出(从那时起它也可能以rx
格式吐出),但我找不到任何这样做的事情,当我应该研究我的论文时,似乎需要做很多工作。 :-)我觉得很难相信没有人这样做过。
以下是我的“改进版”re_pl2el.pl。 -i
表示不要对字符串进行双重转义,-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 ???
答案 2 :(得分:1)
此前最接近的工作是对M-x重建器的扩展,请参阅
http://www.emacswiki.org/emacs/ReBuilder
或叶文斌关于PDE的工作。
http://cpansearch.perl.org/src/YEWENBIN/Emacs-PDE-0.2.16/lisp/doc/pde.html
答案 3 :(得分:0)
可能相关的是visual-regexp-steroids,它扩展了查询替换以使用实时预览,并允许您使用不同的正则表达式后端,包括PCRE。