mirror of https://github.com/swig/swig
Add support for case conversion characters in regex substitutions.
Allow using Perl-like \l, \L, \u, \U and \E escape sequences in the substitution string used with %rename("%(regex:/pattern/subst/)s"). This is useful for e.g. title casing all string after removing some prefix. Closes #82
This commit is contained in:
parent
669a27bb7b
commit
72afb74f47
|
@ -5,6 +5,10 @@ See the RELEASENOTES file for a summary of changes in each release.
|
||||||
Version 3.0.0 (in progress)
|
Version 3.0.0 (in progress)
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
2013-10-15: vadz
|
||||||
|
Allow using \l, \L, \u, \U and \E in the substitution part of %(regex:/pattern/subst/)
|
||||||
|
inside %rename to change the case of the text being replaced.
|
||||||
|
|
||||||
2013-10-12: wsfulton
|
2013-10-12: wsfulton
|
||||||
[Lua] Apply #92 - missing return statements for SWIG_Lua_add_namespace_details()
|
[Lua] Apply #92 - missing return statements for SWIG_Lua_add_namespace_details()
|
||||||
and SWIG_Lua_namespace_register().
|
and SWIG_Lua_namespace_register().
|
||||||
|
|
|
@ -1888,11 +1888,22 @@ and a more descriptive one, but the two functions are otherwise equivalent:
|
||||||
<i>pattern</i> part is a regular expression in Perl syntax (as supported
|
<i>pattern</i> part is a regular expression in Perl syntax (as supported
|
||||||
by the <a href="http://www.pcre.org/">Perl Compatible Regular Expressions (PCRE)</a>)
|
by the <a href="http://www.pcre.org/">Perl Compatible Regular Expressions (PCRE)</a>)
|
||||||
library and the <i>subst</i> string
|
library and the <i>subst</i> string
|
||||||
can contain back-references introduced by <tt>'\'</tt> or, as backslashes need
|
can contain back-references of the form <tt>\N</tt> where <tt>N</tt> is a digit
|
||||||
to be escaped in C strings, rather by <tt>"\\"</tt>. For example, to remove
|
from 0 to 9, or one of the following escape sequences: <tt>\l</tt>, <tt>\L</tt>,
|
||||||
any alphabetic prefix before an underscore you could use the following directive:
|
<tt>\u</tt>, <tt>\U</tt> or <tt>\E</tt>. The back-references are replaced with the
|
||||||
<tt>%rename("regex:/(\\w+)_(.*)/\\2/")</tt></td>
|
contents of the corresponding capture group while the escape sequences perform the
|
||||||
<td><tt>Prefix_Print</tt></td><td><tt>Print</tt></td>
|
case conversion in the substitution string: <tt>\l</tt> and <tt>\L</tt> convert to
|
||||||
|
the lower case, while <tt>\u</tt> and <tt>\U</tt> convert to the upper case. The
|
||||||
|
difference between the elements of each pair is that <tt>\l</tt> and <tt>\u</tt>
|
||||||
|
change the case of the next character only, while <tt>\L</tt> and <tt>\U</tt> do
|
||||||
|
it for all the remaining characters or until <tt>\E</tt> is encountered.
|
||||||
|
|
||||||
|
Finally please notice that backslashes need to be escaped in C strings, so in
|
||||||
|
practice <tt>"\\"</tt> must be used in all these escape sequences. For example,
|
||||||
|
to remove any alphabetic prefix before an underscore and capitalize the remaining
|
||||||
|
part you could use the following directive:
|
||||||
|
<tt>%rename("regex:/(\\w+)_(.*)/\\u\\2/")</tt></td>
|
||||||
|
<td><tt>prefix_print</tt></td><td><tt>Print</tt></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><tt>command:cmd</tt></td>
|
<td><tt>command:cmd</tt></td>
|
||||||
|
|
|
@ -4,9 +4,12 @@ using rename_pcre_encoderNamespace;
|
||||||
public class runme {
|
public class runme {
|
||||||
static void Main() {
|
static void Main() {
|
||||||
SomeWidget w = new SomeWidget();
|
SomeWidget w = new SomeWidget();
|
||||||
w.putBorderWidth(17);
|
w.put_borderWidth(17);
|
||||||
if ( w.getBorderWidth() != 17 )
|
if ( w.get_borderWidth() != 17 )
|
||||||
throw new Exception(String.Format("Border with should be 17, not {0}",
|
throw new Exception(String.Format("Border with should be 17, not {0}",
|
||||||
w.getBorderWidth()));
|
w.get_borderWidth()));
|
||||||
|
|
||||||
|
if ( rename_pcre_encoder.StartINSAneAndUNSAvoryTraNSAtlanticRaNSAck() != 42 )
|
||||||
|
throw new Exception("Unexpected result of renamed function call");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,11 @@ public class rename_pcre_encoder_runme {
|
||||||
public static void main(String argv[])
|
public static void main(String argv[])
|
||||||
{
|
{
|
||||||
SomeWidget w = new SomeWidget();
|
SomeWidget w = new SomeWidget();
|
||||||
w.putBorderWidth(17);
|
w.put_borderWidth(17);
|
||||||
if ( w.getBorderWidth() != 17 )
|
if ( w.get_borderWidth() != 17 )
|
||||||
throw new RuntimeException(String.format("Border with should be 17, not %d",
|
throw new RuntimeException(String.format("Border with should be 17, not %d",
|
||||||
w.getBorderWidth()));
|
w.get_borderWidth()));
|
||||||
|
if ( rename_pcre_encoder.StartINSAneAndUNSAvoryTraNSAtlanticRaNSAck() != 42 )
|
||||||
|
throw new RuntimeException("Unexpected result of renamed function call");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
from rename_pcre_encoder import *
|
from rename_pcre_encoder import *
|
||||||
|
|
||||||
s = SomeWidget()
|
s = SomeWidget()
|
||||||
s.putBorderWidth(3)
|
s.put_borderWidth(3)
|
||||||
if s.getBorderWidth() != 3:
|
if s.get_borderWidth() != 3:
|
||||||
raise RuntimeError("Border should be 3, not %d" % (s.getBorderWidth(),))
|
raise RuntimeError("Border should be 3, not %d" % (s.get_borderWidth(),))
|
||||||
|
|
||||||
s.putSize(4, 5)
|
s.put_size(4, 5)
|
||||||
a = AnotherWidget()
|
a = AnotherWidget()
|
||||||
a.DoSomething()
|
a.DoSomething()
|
||||||
|
|
||||||
evt = wxEVTSomeEvent()
|
evt = wxEVTSomeEvent()
|
||||||
t = xUnchangedName()
|
t = xUnchangedName()
|
||||||
|
|
||||||
|
if StartINSAneAndUNSAvoryTraNSAtlanticRaNSAck() != 42:
|
||||||
|
raise RuntimeError("Unexpected result of renamed function call")
|
||||||
|
|
|
@ -3,9 +3,14 @@
|
||||||
// strip the wx prefix from all identifiers except those starting with wxEVT
|
// strip the wx prefix from all identifiers except those starting with wxEVT
|
||||||
%rename("%(regex:/wx(?!EVT)(.*)/\\1/)s") "";
|
%rename("%(regex:/wx(?!EVT)(.*)/\\1/)s") "";
|
||||||
|
|
||||||
// Replace "Set" and "Get" prefixes with "put" and "get" respectively.
|
// Change "{Set,Get}Foo" naming convention to "{put,get}_foo" one.
|
||||||
%rename("%(regex:/^Set(.*)/put\\1/)s", %$isfunction) "";
|
%rename("%(regex:/^Set(.*)/put_\\l\\1/)s", %$isfunction) "";
|
||||||
%rename("%(regex:/^Get(.*)/get\\1/)s", %$isfunction) "";
|
%rename("%(regex:/^Get(.*)/get_\\l\\1/)s", %$isfunction) "";
|
||||||
|
|
||||||
|
// Make some words stand out (unfortunately we don't have "global" flag): we
|
||||||
|
// use \U to capitalize the second capture group and then \E to preserve the
|
||||||
|
// case of the rest.
|
||||||
|
%rename("%(regex:/(.*?)(nsa)(.*?)\\2(.*?)\\2(.*?)\\2(.*)/\\1\\U\\2\\E\\3\\U\\2\\E\\4\\U\\2\\E\\5\\U\\2\\E\\6/)s") "";
|
||||||
|
|
||||||
%inline %{
|
%inline %{
|
||||||
|
|
||||||
|
@ -28,4 +33,6 @@ class wxEVTSomeEvent {
|
||||||
class xUnchangedName {
|
class xUnchangedName {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline int StartInsaneAndUnsavoryTransatlanticRansack() { return 42; }
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -1180,8 +1180,38 @@ err_out:
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function copies len characters from src to dst, possibly applying case conversions to them: if convertCase is 1, to upper case and if it is -1, to lower
|
||||||
|
* case. If convertNextOnly is 1, only a single character is converted (and convertCase is reset), otherwise all of them are. */
|
||||||
|
static void copy_with_maybe_case_conversion(String *dst, const char *src, int len, int *convertCase, int convertNextOnly)
|
||||||
|
{
|
||||||
|
/* Deal with the trivial cases first. */
|
||||||
|
if (!len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!*convertCase) {
|
||||||
|
Write(dst, src, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we must convert only the first character, do it and write the rest at once. */
|
||||||
|
if (convertNextOnly) {
|
||||||
|
Putc(*convertCase == 1 ? toupper(*src) : tolower(*src), dst);
|
||||||
|
*convertCase = 0;
|
||||||
|
if (len > 1) {
|
||||||
|
Write(dst, src + 1, len - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* We need to convert all characters. */
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++, src++) {
|
||||||
|
Putc(*convertCase == 1 ? toupper(*src) : tolower(*src), dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String *replace_captures(int num_captures, const char *input, String *subst, int captures[], String *pattern, String *s)
|
String *replace_captures(int num_captures, const char *input, String *subst, int captures[], String *pattern, String *s)
|
||||||
{
|
{
|
||||||
|
int convertCase = 0, convertNextOnly = 0;
|
||||||
String *result = NewStringEmpty();
|
String *result = NewStringEmpty();
|
||||||
const char *p = Char(subst);
|
const char *p = Char(subst);
|
||||||
|
|
||||||
|
@ -1189,10 +1219,10 @@ String *replace_captures(int num_captures, const char *input, String *subst, int
|
||||||
/* Copy part without substitutions */
|
/* Copy part without substitutions */
|
||||||
const char *q = strchr(p, '\\');
|
const char *q = strchr(p, '\\');
|
||||||
if (!q) {
|
if (!q) {
|
||||||
Write(result, p, strlen(p));
|
copy_with_maybe_case_conversion(result, p, strlen(p), &convertCase, convertNextOnly);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Write(result, p, q - p);
|
copy_with_maybe_case_conversion(result, p, q - p, &convertCase, convertNextOnly);
|
||||||
p = q + 1;
|
p = q + 1;
|
||||||
|
|
||||||
/* Handle substitution */
|
/* Handle substitution */
|
||||||
|
@ -1203,12 +1233,39 @@ String *replace_captures(int num_captures, const char *input, String *subst, int
|
||||||
if (group < num_captures) {
|
if (group < num_captures) {
|
||||||
int l = captures[group*2], r = captures[group*2 + 1];
|
int l = captures[group*2], r = captures[group*2 + 1];
|
||||||
if (l != -1) {
|
if (l != -1) {
|
||||||
Write(result, input + l, r - l);
|
copy_with_maybe_case_conversion(result, input + l, r - l, &convertCase, convertNextOnly);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Swig_error("SWIG", Getline(s), "PCRE capture replacement failed while matching \"%s\" using \"%s\" - request for group %d is greater than the number of captures %d.\n",
|
Swig_error("SWIG", Getline(s), "PCRE capture replacement failed while matching \"%s\" using \"%s\" - request for group %d is greater than the number of captures %d.\n",
|
||||||
Char(pattern), input, group, num_captures-1);
|
Char(pattern), input, group, num_captures-1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/* Handle Perl-like case conversion escapes. */
|
||||||
|
switch (*p) {
|
||||||
|
case 'u':
|
||||||
|
convertCase = 1;
|
||||||
|
convertNextOnly = 1;
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
convertCase = 1;
|
||||||
|
convertNextOnly = 0;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
convertCase = -1;
|
||||||
|
convertNextOnly = 1;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
convertCase = -1;
|
||||||
|
convertNextOnly = 0;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
convertCase = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Swig_error("SWIG", Getline(s), "Unrecognized escape character '%c' in the replacement string \"%s\".\n",
|
||||||
|
*p, Char(subst));
|
||||||
|
}
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue