Eclipse Conditional replace with regex - regex

Given the text
public void MyFunction(int i, String str, boolean doIt) {
Log.i(TAG, "Enter MyFunction(int i, String str, boolean doIt)");
I want to make some replacements on the second line, but not the first
public void MyFunction(int i, String str, boolean doIt) {
Log.i(TAG, "Enter MyFunction( i:" + i + ", str:" + str ", doIt:" + doIt + ")");
So far using the following regex I manage to get these results:
find "\w+\s+(\w+)([,\)])"
replace with "$1:" + $1 + "$2"
public void MyFunction(i:" + i + ", str:" + str ", doIt:" + doIt + ") ") {
Log.i(TAG, "Enter MyFunction( i:" + i + ", str:" + str ", doIt:" + doIt + ") ");
Is there any way to force the replace to be executed only on the Log.i lines?
EDIT:
I tried the following regex
"Log\.i\(.*?\((\s*(\w+\s+(\w+)([,\)]))+"
but $1,$2,$3 only contains the last match (the last argument: doIt)
$1=boolean doIt)
$2=doIt
$3=)
when there should be 3 sets of $1,$2,$3, one for each argument.
If you know how to retrieve multiple matches, that would also make for a solution

I caved,
I used this little perl to do the job:
next unless /Log\.i/;
s/TAG,/TAGG/;
s/(final\s+)?[^ \(]+\s+(\w+)([,\)])/$2:\" \+ $2 \+ \"$3/g;
s/TAGG/TAG,/;
with the command line:
perl -pi <scriptname> <file>
If someone still wants to contribute some, I understand I could have run perl as Eclipse external tool to process the java files. How do I do that?
UPDATE:
I wrote a post on how to use external perl to run the script from within Eclipse IDE
see the post

Related

Removing expressions from QString using QRegExp

I'm having an issue removing expressions from a QString using QRegExp. I tried a countless number of regex to no avail. What am I doing wrong?
Sample Text (QString myString) In this instance, myString contains "\u0006\u0007\u0013Hello".
myString.remove(QRegExp("\\[u][0-9]{4}"));
It does not remove any instances of \uXXXX where X = numbers.
However, when I am specific such as:
myString.remove("\u0006");
It does remove it.
String literals are not always the same as character sequence
for (char c : "\u0006\u0007\u0013Hello".toCharArray()) {
System.out.println( c + " (" + (int)c + ")" );
}
System.out.println( "--------------" );
for (char c : "\\u0006\\u0007\\u0013Hello".toCharArray()) {
System.out.println( c + " (" + (int)c + ")" );
}
In the first example \u0006 is encoding an unicode code point, whereas in second the string actually contains a backslash.
The string literal only exist at compile time, at runtime they are character sequences.
Regexes are working over character sequence not over string litteral, and also backlash have special meaning and need to be escaped.
Also note that \u0041 is another way to encode A.
Maybe what you are looking for are unicode categories, maybe following can help:
string.replaceAll( "\\p{Cc}", "" )

backslash gets to end of string when appending double quotes

I'm finishing up a c++ program and have one last issue that I can't seem to find a fix for. I had the code cpcmd += '"' + path + '"' + " " + '"' + dek + '"'
after finding a question similar to mine I tried the following.
cpcmd += "\"" + path + "\"" + " " + "\"" + dek + "\""
cpcmd += \" + path + \" + " " + \" + dek + \"
The latter of which doesn't even compile.If I could avoid using double quotes I would but I need to pass commands to cmd.
Why does adding double quotes the first way I tried cause an extra \ to be added to the end of the string I'm appending to? It gets added between the double quote and the end of the string it's being appended to.
In answer to the comment yes cpcmd is a string all variables here are.
I knew I'd be downvoted but I don't understand why. If I was able to find an answer to this question from googling I wouldn't have asked it.
In answer to comment asking for a full example the following will produce what I'm talking about in the debugger.
i
#include <iostream>
#include <string>
int main()
{
std::string test = "this is a string";
test += '"';
std::cout << test;
}
Update: My apologies I got caught in looking at the debugger so much that I assumed that what's exactly shown in it for the values of the local variables is what gets passed. Again I'm sorry please don't downvote this anymore. I've voted myself to have it deleted.

Cleaning up formatting after deletion using regex

I have a function similar to the one below appearing in multiple files. I want to use regex to get rid of all references to outputString, since clearly, they're wasteful.
... other functions, class declarations, etc
public String toString()
{
String outputString = "";
return ... some stuff
+ outputString;
}
... other functions, class declarations, etc
I'm happy to do this in multiple passes. So far I've got regexes to find the first and last line (String outputString = "";$ and ( \+ outputString;)$). However, I've got two problems: first, I want to get rid of the whitespace that results in deleting the two lines that refer to outputString. Second, I need the final ; on the second last line to move up to the line above it.
As a bonus, I'd also like to know what's wrong with adding the line start anchor (^) to either of the regexes I specified. It seems like doing so would tighten them up, but when I try something like ^( \+ outputString;)$ I get zero results.
After all's said and done the function above should look like this:
... other functions, class declarations, etc
public String toString()
{
return ... some stuff;
}
... other functions, class declarations, etc
Here's an example of what "some stuff" might be:
"name" + ":" + getName()+ "," +
"id" + ":" + getId()+ "]" + System.getProperties().getProperty("line.separator") +
" " + "student = "+(getStudent()!=null?Integer.toHexString(System.identityHashCode(getStudent())):"null")
Here's a concrete example:
Current:
public void delete()
{
Student existingStudent = student;
student = null;
if (existingStudent != null)
{
existingStudent.delete();
}
}
public String toString()
{
String outputString = "";
return super.toString() + "["+
"name" + ":" + getName()+ "," +
"id" + ":" + getId()+ "]" + System.getProperties().getProperty("line.separator") +
" " + "student = "+(getStudent()!=null?Integer.toHexString(System.identityHashCode(getStudent())):"null")
+ outputString;
}
public String getId()
{
return id;
}
Required:
public void delete()
{
Student existingStudent = student;
student = null;
if (existingStudent != null)
{
existingStudent.delete();
}
}
public String toString()
{
return super.toString() + "["+
"name" + ":" + getName()+ "," +
"id" + ":" + getId()+ "]" + System.getProperties().getProperty("line.separator") +
" " + "student = "+(getStudent()!=null?Integer.toHexString(System.identityHashCode(getStudent())):"null");
}
public String getId()
{
return id;
}
1st pass:
Find:
.*outputString.*\R
Replace with empty string.
Demo:
https://regex101.com/r/g3aYnp/2
2nd pass:
Find:
(toString\(\)[\s\S]+\))(\s*\R\s*?\})
Replace:
$1;$2
https://regex101.com/r/oxsNRW/3
Assuming that the wanted part of the return expression does not contain any semi colons (i.e. ;) then you can do it in one replace. Search for:
^ +String outputString = "";\R( +return [^;]+?)\R +\+ outputString;
and replace with:
\1;
The idea is to match all three lines in one go, to keep the wanted part and to add the ;.
An interesting point in this replacement. My first attempt had ... return [^;]+)\R +\+ ... and it failed whereas ... return [^;]+)\r\n +\+ ... worked. The \R version appeared to leave a line-break before the final ;. Turning on menu => View => Show symbol => Show end of line reveals that the greedy term within the capture group collected the \r and the \R matched only the \n. Changing to a non-greedy form allowed the \R to match the entire \r\n.

Sublime Snippet Regex Replacement

I've recently been creating quite a few Sublime Text 3 plugins/snippets/etc. to automate repetitive tasks. The current one I am stuck on uses regex in a snippet to get my default skeleton for a new function.
Ideally, I would like the snippet would generate something similar to:
// Multiple Args (one arg would obviously look like (..." + "a: " + a + ")");)
function Foo(a, b, c)
{
Log.AppendFolder("Foo(" + "a: " + a + ", b: " + b + ", c: " + c + ")");
//body
Log.PopLogFolder();
}
// Zero Args
function Foo()
{
Log.AppendFolder("Foo()");
//body
Log.PopLogFolder();
}
So far, I can get it formatted with 1 argument or many arguments, not all possible combos (zero, one, many).
The outline is current this, I just need to figure out the second ${2} with regex:
<snippet>
<content><![CDATA[
function ${1:function_name}(${2:arguments})
{
Log.AppendFolder("$1(" + ${2/(?#stuck here)//} + ")");
${3://body}
Log.PopLogFolder();
}$0]]></content>
<tabTrigger>fun</tabTrigger>
<scope>source.js</scope>
<description>Function Template</description>
</snippet>
One Arg:
"$1(" + ${2/^([A-z0-9_-]*),?.*/"\1\: " + \1 + /}");"
Many Args (with 1 arg, this shows "a: " + a + a):
"$1(" + ${2/^([A-z0-9_-]*),?(.*)/"\1\: " + \1 + /}${2/([A-z0-9_-]*)(?:, *([A-z0-9_-]*))/"$2\: " + $2 + /g}");"
One method worked by had an extra + "" + in there, which I'd like to avoid:
${2/([A-z_0-9]+)((?:, ?)?)/"\1\: " + \1 + "\2" + /g}
I've tried a conditional look-ahead based on commas, but that gets messed up >1 arg, probably due to my lack of understanding of them:
${2/(?(?!,)^([A-z0-9_-]*)$|([A-z0-9_-]*), *)/"\1\: " + \1/g}
I could easily do this via a normal plugin (this is easy programmatically), but ideally this can remain a snippet/code-completion since I can just override the JS "fun" code-completion.
What am I missing to accomplish this (or is it simply the wrong avenue - if that's the case, I'd still like to know to learn more about regex)?
Finally figured this out, there is a conditional replacement option:
?n:then:else
So the final format looks like:
<snippet>
<content><![CDATA[
function ${1:function_name}(${2:args})
{
Log.AppendFolder("$1(${2/.+/" + /}${2/([A-z_0-9-]+) *(,)? */"$1\: " + $1 ?2: + "$2 " + :+ /g}${2/.+/"/})");
${3:// body...}
Log.PopLogFolder();
}$0]]></content>
<tabTrigger>fun</tabTrigger>
<scope>source.js</scope>
<description>Function</description>
</snippet>
Which will give the desired result:
function function_name()
{
Log.AppendFolder("function_name()");
// body...
Log.PopLogFolder();
}
function function_name(a)
{
Log.AppendFolder("function_name(" + "a: " + a + ")");
// body...
Log.PopLogFolder();
}
function function_name(a, b)
{
Log.AppendFolder("function_name(" + "a: " + a + ", " + "b: " + b + ")");
// body...
Log.PopLogFolder();
}

How do I exclude a directory using regular expressions?

I asked a question a little while ago about using regular expressions to extract a match from a URL in a particular directory.
eg: www.domain.com/shop/widgets/match/
The solution given was ^/shop.*/([^/]+)/?$
This would return "match"
However, my file structure has changed and I now need an expression that instead returns "match" in any directory excluding "pages" and "system"
Basically I need an expression that will return "match" for the following:
www.domain.com/shop/widgets/match/
www.domain.com/match/
But not:
www.domain.com/pages/widgets/match/
www.domain.com/pages/
www.domain.com/system/widgets/match/
www.domain.com/system/
I've been struggling for days without any luck.
Thanks
This is just an alternative to Grahams great answer above. Code in C# (but fot the regex part, that doesn't matter):
void MatchDemo()
{
var reg = new Regex("( " +
" (\\w+[.]) " +
" | " +
" (\\w+[/])+ " +
") " +
"(shop[/]|\\w+[/]) " + //the URL-string must contain the sequence "shop"
"(match) " ,
RegexOptions.IgnorePatternWhitespace);
var url = #"www.domain.com/shop/widgets/match/";
var retVal = reg.Match(url).Groups[5]; //do we have anything in the fifth parentheses?
Console.WriteLine(retVal);
Console.ReadLine();
}
/Hans
BRE and ERE do not provide a way to negate a portion of the RE, except within a square bracket expression. That is, you can [^a-z], but you can't express not /(abc|def)/. If your regex dialiect is ERE, then you must use two regexps. If you're using PREG, you can use a negative look-ahead.
For example, here's some PHP:
#!/usr/local/bin/php
<?php
$re = '/^www\.example\.com\/(?!(system|pages)\/)([^\/]+\/)*([^\/]+)\/$/';
$test = array(
'www.example.com/foo/bar/baz/match/',
'www.example.com/shop/widgets/match/',
'www.example.com/match/',
'www.example.com/pages/widgets/match/',
'www.example.com/pages/',
'www.example.com/system/widgets/match/',
'www.example.com/system/',
);
foreach ($test as $one) {
preg_match($re, $one, $matches);
printf(">> %-50s\t%s\n", $one, $matches[3]);
}
And the output:
[ghoti#pc ~]$ ./phptest
>> www.example.com/foo/bar/baz/match/ match
>> www.example.com/shop/widgets/match/ match
>> www.example.com/match/ match
>> www.example.com/pages/widgets/match/
>> www.example.com/pages/
>> www.example.com/system/widgets/match/
>> www.example.com/system/
Is that what you're looking for?