Homepage: https://github.com/k-talo/foreign-regexp.el
Updated:
Search and replace by foreign regexp
CAUTION
=======
THIS LIBRARY IS VERY EXPERIMENTAL, SO YOU MAY HAVE MANY
PROBLEM WITH THIS LIBRARY. AND THIS LIBRARY COMES WITH
NO WARRANTY.
OVERVIEW
========
This library provides a feature, processing regular
expressions in manner of other programming languages
(we call it `foreign regexp' for convenience here),
to Emacs.
In particular, this library provides features corresponds to
such as `isearch-forward-regexp', `query-replace-regexp' and
`occur'.
Currently, regular expressions of Perl, Ruby, JavaScript and
Python can be used as foreign regexp.
THE GUTS OF THIS LIBRARY
========================
This library works like below:
1. Make a search/replace operation with foreign regexp
through the user-interface of Emacs.
2. A search/replace operation will be executed by external
commands (they are implemented in Perl, Ruby, JavaScript
or Python).
3. Apply the result of search/replace operations to the buffer
through the user-interface of Emacs.
REQUIREMENTS
============
You need to have an Emacs which running on UNIX-like operating
system (*BSD/Linux/MacOSX) or Windows+Cygwin.
perl (>= 5.8), ruby (>= 1.9) node (Node.js, for JavaScript) or
python (only tested on 2.x), choose one of them as your taste,
is required as external command.
Also features `cl', `menu-bar' and `re-builder' are required.
For better multilingual support, Emacs (>= 21) may be required.
NOTE (for Windows users):
In some cases, virus scanner program makes each `foreign-regexp'
command running extremely slow.
On such case, turn off virus scanner program, or exclude the
path which is specified by a variable `foreign-regexp/tmp-dir'
from virus scanning.
This may improve the response of each `foreign-regexp' command.
INSTALLING
==========
To install this library, save this file to a directory in your
`load-path' (you can view the current `load-path' using
`C-h v load-path ' within Emacs), then add following
lines to your `.emacs':
(require 'foreign-regexp)
(custom-set-variables
'(foreign-regexp/regexp-type 'perl) ;; Choose your taste of foreign regexp
;; from 'perl, 'ruby, 'javascript or
;; 'python.
'(reb-re-syntax 'foreign-regexp)) ;; Tell re-builder to use foreign regexp.
USAGE EXAMPLE
=============
In these examples, we suppose the contents of curent buffer are:
123---789
[Example-1] Query Replace in manner of Perl.
STEP-1: Set `foreign-regexp/regexp-type' to Perl.
`M-x foreign-regexp/regexp-type/set perl '
NOTE: Once you choose REGEXP-TYPE, Emacs will remember it
until exit. You can also set and save REGEXP-TYPE for
next Emacs session by setting value via customize.
See "COMMANDS (1) SETTING REGEXP-TYPE" section in
this document.
STEP-2: Run query replace
`M-s M-% (\d+)---(\d+) ${1}456${2} '
This command replaces the text in buffer:
123---789
with text:
123456789
NOTE: Variables in replacement string are interpolated by Perl.
[Example-2] Query Replace in manner of Ruby.
STEP-1: Set regexp-type to Ruby.
`M-x foreign-regexp/regexp-type/set ruby '
STEP-2: Run query replace
`M-s M-% (\d+)---(\d+) #{$1}456#{$2} '
This command replaces text in buffer:
123---789
with text:
123456789
Variables in replacement string are interpolated by ruby
as if they are in the replacement string inside of the
`String#gsub' method.
[Example-3] Query Replace in manner of JavaScript.
STEP-1: Set regexp-type to JavaScript.
`M-x foreign-regexp/regexp-type/set javascript '
STEP-2: Run query replace
`M-s M-% (\d+)---(\d+) $1456$2 '
This command replaces text in buffer:
123---789
with text:
123456789
Variables in replacement string are interpolated
as if they are in `String.prototype.replace' method.
[Example-4] Query Replace in manner of Python.
STEP-1: Set regexp-type to Python.
`M-x foreign-regexp/regexp-type/set python '
STEP-2: Run query replace
`M-s M-% (\d+)---(\d+) \g<1>456\g<2> '
This command replaces text in buffer:
123---789
with text:
123456789
Backreferences in replacement string are interpolated
as if they are in `re.sub' method.
COMMANDS(1): SETTING REGEXP-TYPE
================================
`M-x foreign-regexp/regexp-type/set REGEXP-TYPE '
Set type of regexp syntax to REGEXP-TYPE.
By default, four regexp-types `perl', `ruby', `javascript' and
`python' are provided.
You can also set REGEXP-TYPE via customization interface:
`M-x customize-apropos foreign-regexp/regexp-type '
COMMANDS(2): SEARCH AND REPLACEMENT
===================================
NOTE: While editing a regular expression on the minibuffer prompt
of `foreign-regexp' commands below, you can switch to another
`foreign-regexp' command without losing current editing state.
`M-s M-o REGEXP '
`M-x foreign-regexp/occur REGEXP '
Show all lines in the current buffer containing a match
for foreign REGEXP.
`M-s M-% REGEXP REPLACEMENT '
`M-x foreign-regexp/query-replace REGEXP REPLACEMENT '
Replace some matches for foreign REGEXP with REPLACEMENT.
Note that notation of REPLACEMENT is different for
each REGEXP-TYPE.
`M-s M-s'
`M-x foreign-regexp/isearch-forward '
Begin incremental search for a foreign regexp.
`M-s M-r'
`M-x foreign-regexp/isearch-backward REGEXP'
Begin reverse incremental search for a foreign regexp.
`M-s M-f REGEXP '
`M-x foreign-regexp/non-incremental/search-forward REGEXP '
Search for a foreign REGEXP.
`M-s M-F REGEXP '
`M-x foreign-regexp/non-incremental/search-backward REGEXP '
Search for a foreign REGEXP backward.
`M-s M-g'
`M-x nonincremental-repeat-search-forward'
Search forward for the previous search string or regexp.
`M-s M-G'
`M-x nonincremental-repeat-search-backward'
Search backward for the previous search string or regexp.
COMMANDS(3): WORKING WITH SEARCH OPTIONS
========================================
NOTE: The status of each search option will be displayed by an
indicator which is put on the minibuffer prompt of each
`foreign-regexp' command, or put on the mode-line of a
buffer `*RE-Builder*'. The indicator will be displayed
like these: `[isxe]' for Perl, `[imxe]' for Ruby,
`[ie]' for JavaScript and [ISXe] for Python.
`M-s M-i'
`M-x foreign-regexp/toggle-case-fold '
Toggle search option `case-fold-search'.
`M-s M-m'
`M-x foreign-regexp/toggle-dot-match '
Toggle search option `foreign-regexp/dot-match-a-newline-p'.
`M-s M-x'
`M-x foreign-regexp/toggle-ext-regexp '
Toggle search option `foreign-regexp/use-extended-regexp-p'.
`M-s M-e'
`M-x foreign-regexp/toggle-eval-replacement '
Toggle search option `foreign-regexp/eval-replacement-p'.
When this search option is on, the replacement string for
a command `foreign-regexp/query-replace' will be evaluated
as expression. For example, these commands:
For `Perl':
`M-s M-% ^ no strict 'vars';sprintf('%05d: ', ++$LINE) '
NOTE:
Replacement will be evaluated like REPLACEMENT in replacement
operator with `e' option (like: `s/pattern/REPLACEMENT/e').
In the replacement string, you can refer to special variables
`$&', `$1', `&2', ... and so on.
For `Ruby':
`M-s M-% ^ { $LINE||=0;sprintf('%05d: ', $LINE+=1) } '
NOTE:
Replacement will be evaluated like a block passed to
`String#gsub' method.
In the block form, the current match string is passed as a
parameter, and you can refer to built-in variables `$&', `$1',
`&2', ... and so on.
For `JavaScript':
`M-s M-% ^ function (m) {if(typeof(i)=='undefined'){i=0};return ('0000'+(++i)).substr(-5)+': '} '
NOTE:
Replacement will be evaluated like a function in the 2nd
argument of the method =String.prototype.replace=.
In the function, the current match string, captured strings
(1 .. nth, if exits), the position where the match occurred, and
the strings to be searched are passed as arguments, and you can
refer to properties `RegExp.lastMatch', `RegExp.$1', ... and
so on.
For `Python':
`M-s M-% ^ i = 0 C-q C-j def f (m): C-q C-j global i
C-q C-j i=i+1 C-q C-j return '%05d: ' % i '
NOTE:
You can specify a function which takes match object as argument
and returns replacement string, by `lambda' expression or `def'
statement.
And you can refer match and sub groups through match object,
for example: `lambda m: m.group(0)'.
When you specify a function by `def' statement, you can use
arbitrary function name and you can put statements around the
function.
In this case, the first `def' statement will be called for each
matches, and the other statements will be called only once
before search/replacement operation has began.
The first implementation of this library accepts only `lambda'
expression as the replacement.
Because of inconvenience of =lambda= expression, that it does
not accept any statement like assignment operation, so we make
this library to accept =def= statement.
Additionally, we can't assign to uninitialized global variable
in function defined by =def= statement, so we make it to accept
statements around the =def= statement which can initialize
global variables, for our convenience.
put line number to beginning of each lines.
COMMANDS(4): CONSTRUCTING REGEXP WITH RE-BUILDER
================================================
`M-x reb-change-syntax foreign-regexp '
Set the syntax used by the `re-builder' to foreign regexp.
`M-s M-l'
`M-x re-builder '
Start an interactive construction of a foreign regexp with
`re-builder'.
(See also documents of `re-builder')
NOTE-1: To apply the foreign regexp, which was constructed
with `re-builder', to the `foreign-regexp' commands,
call commands below in `*RE-Builder*' buffer:
`M-s M-o'
`M-x foreign-regexp/re-builder/occur-on-target-buffer'
Run `foreign-regexp/occur' in `reb-target-buffer'
with a foreign regexp in the buffer `*RE-Builder*'.
`M-s M-%'
`M-x foreign-regexp/re-builder/query-replace-on-target-buffer'
Run `foreign-regexp/query-replace' in `reb-target-buffer'
with a foreign regexp in the buffer `*RE-Builder*'.
`M-s M-s'
`M-x foreign-regexp/re-builder/isearch-forward-on-target-buffer'
Run `foreign-regexp/isearch-forward' in `reb-target-buffer'
with a foreign regexp in the buffer `*RE-Builder*'.
`M-s M-r'
`M-x foreign-regexp/re-builder/isearch-backward-on-target-buffer'
Run `foreign-regexp/isearch-backward' in `reb-target-buffer'
with a foreign regexp in the buffer `*RE-Builder*'.
`M-s M-f'
`M-x foreign-regexp/re-builder/non-incremental-search-forward-on-target-buffer'
Run `foreign-regexp/non-incremental/search-forward' in `reb-target-buffer'
with a foreign regexp in the buffer `*RE-Builder*'.
`M-s M-F'
`M-x foreign-regexp/re-builder/non-incremental-search-backward-on-target-buffer'
Run `foreign-regexp/non-incremental/search-backward' in `reb-target-buffer'
with a foreign regexp in the buffer `*RE-Builder*'.
NOTE-2: You can switch search options of the
`reb-target-buffer' with commands below:
`M-s M-i'
`M-x foreign-regexp/re-builder/toggle-case-fold-on-target-buffer'
Toggle search option `case-fold-search' of `reb-target-buffer'.
`M-s M-m'
`M-x foreign-regexp/re-builder/toggle-dot-match-on-target-buffer'
Toggle search option `foreign-regexp/dot-match-a-newline-p'
of `reb-target-buffer'.
`M-s M-x'
`M-x foreign-regexp/re-builder/toggle-ext-regexp-on-target-buffer'
Toggle search option `foreign-regexp/use-extended-regexp-p'
of `reb-target-buffer'..
`M-\'
`M-x foreign-regexp/quote-meta-in-region '
Escape characters in region, that would have special meaning
in foreign regexp.
COMMANDS(5): ALIGNMENT USING FOREIGN REGEXP
===========================================
`C-M-|'
`M-x align'
Align region according to pre-defined alignment rules.
Foreign regexp can be used in a rule by putting an
`regexp-type' attribute on the alignment rule.
Example)
(add-to-list
'align-rules-list
'(perl-and-ruby-hash-form
;; This rule will be applied when `regexp-type'
;; is `perl' or `ruby'.
(regexp-type . '(perl ruby))
(regexp . "([ \\t]*)=>[ \\t]*[^# \\t\\n]") ;; Foreign Regexp
(group . 1)
(repeat . t)
(modes . '(perl-mode cperl-mode ruby-mode))))
See also `align-rules-list' and help document of an advice
of `align-region' for more information about alignment rules.
`M-s M-a REGEXP '
`M-x foreign-regexp/align REGEXP '
Align the current region using a partial foreign regexp
read from the minibuffer.
The foreign regexp read from the minibuffer will be
supposed to be placed after whitespaces.
See also `align-regexp'.
`C-u M-s M-a REGEXP GROUP SPACING REPEAT '
`C-u M-x foreign-regexp/align REGEXP GROUP SPACING REPEAT '
Align the current region using an ad-hoc rule read from the minibuffer.
Example)
< Use perl-style foreign regexp in this example. >
When texts in region is:
(one 1)
(ten 10)
(hundred 100)
(thousand 1000)
Run command on the region with options:
REGEXP: ([ \t]+)\d
|
+--- GROUP: 1
Alignment will be applied to each
lines by inserting white-spaces to
the place where the capture group
specified by `GROUP' is matched to.
SPACING: 1
REPEAT: y
Result is:
(one 1)
(ten 10)
(hundred 100)
(thousand 1000)
|
+---- Aligned using SPACING spaces.
See also `align-regexp'.
FOR HACKERS
===========
You can use regexp syntax of your choice of language, if you
write four external commands below with the language:
`foreign-regexp/replace/external-command'
`foreign-regexp/occur/external-command'
`foreign-regexp/search/external-command'
`foreign-regexp/quote-meta/external-command'
and install these commands with the function
`foreign-regexp/regexp-type/define'.
See help documents of these variables and functions
for more information.
KNOWN PROBLEMS
==============
Codes aside, this document should be rewritten.
My English sucks :-(
WISH LIST
=========
- History for `re-builder'.
- `grep' with foreign regexp?
- `tags-search', `tags-query-replace', `dried-do-search' and
`dired-do-query-replace-regexp' with foreign regexp?
- `multi-isearch-buffers-regexp', `multi-occur',
`multi-occur-in-matching-buffers', `how-many', `flush-lines',
and `keep-lines' with foreign regexp?
- Better error messages.
- Write Tests.