Finding a Part of a String and Replacing the Whole String

a = "hi everyone,

i'd like to take a large block of text and find every instance[0] of a certain word, in this case, instance[1] - and i'd like to replace every instance[2] number with another number, let's say [3]. string.replace doesn't quite cut it..
 
anyone able to help? " 

Sounds like fun! I don’t fully understand your example, but maybe you can build something with the help of

http://doc.sccode.org/Classes/ArrayedCollection.html#-indexOf

where you collect parts of the string up to and including the first occurrence, do the manipulation, perform the same on the rest of the string, and then glue them together

Most likely there are other more elegant ways in sc, I’d be interested in hearing about them

Cheers,
eddi
https://alln4tural.bandcamp.com

I also don’t fully understand the details of your example (e.g. do you want to replace “instance[0]” with “instance[3]”, or the whole thing with “3”, or what? Anyhow, it doesn’t really matter, you can do whatever complex searches/matches you want using regular expressions, and then substitute things as desired. For example, here I’ll show an example of how to replace just numbers in brackets, if there are any brackets immediately after the word “instance”… For fun, I’ll replace any integers there by the word “three”.

(
a = "hi everyone,

i'd like to take a large block of text and find every instance[0] of
a certain word, in this case, instance[1] - and i'd like to replace
every instance[2] number with another number, let's say [3].
string.replace doesn't quite cut it..
 
anyone able to help? "
)

(
a.findRegexp("instance\\[(\\d+)\\]").clump(2).reverse.do{ arg match;
	var offset = match[1][0], matchStr = match[1][1];
	a = a.replaceAt("three", offset, matchStr.size)
};
a.postcs; nil
)

The findRegexp call returns a list of matches (in my regular expression, there are actually two list entries returned per match – the overall match followed by a sub-match of the integer in brackets). That’s why I do clump(2), and then I reverse it to work backwards, so I can manipulate the a string repeatedly without invalidating any “later” indices.

Result:

"hi everyone,

i'd like to take a large block of text and find every instance[three] of
a certain word, in this case, instance[three] - and i'd like to replace
every instance[three] number with another number, let's say [3].
string.replace doesn't quite cut it..
 
anyone able to help? "

If you’re not familiar with regular expressions, this probably won’t make a lot of sense. I would recommend the excellent website regex101 to test them out, and to learn more.

Hope that’s helpful,
Glen.

1 Like

I once added some missing functionality in strings, which may help in achieving your goals (but like the others, I do not understand the exact requirement): you can find installation instructions and a small demo here some missing string operations: split on regex; replace regex; between regex

2 Likes

I’ll try and explain the details:
I am saving a text file with code in it, but I’d like to be able to open the code in different iterations, so I am trying to write some kind of parsing mechanism so that the current iteration replaces the saved iteration.

Now, I’m thinking that instead of dealing with it as an array, specifically, it actually makes more sense to deal with it along the lines of “instance1_0”, “instance2_0”, “instance3_0”…

Visiting the regex101 site, I managed to come up with a new search term - but I think I’m still making a mistake somewhere…

(
a = "
nothing here..
variation1_0;
variation3_0;
variation2_0;
nothing here either.
";

)

(
a.findRegexp("variation\\d_\\d").clump(2).reverse.do{ arg match;
var offset = match[1][0], matchStr = match[1][1];
a = a.replaceAt("4", offset, matchStr.size)
};
a.postcs;
)

Thanks, everyone!

Sorry it still isn’t clear to me. It’s best to explain it without any ambiguity: e.g. by showing a sample input and the desired output.

oh sure…

(
//sample input
a = "
nothing here..
variation1_0;
variation3_0;
variation2_0;
nothing here either.
";
//sample output
b = "
nothing here..
variation1_4;
variation3_4;
variation2_4;
nothing here either.
";

Nevermind. I got it! I will spend some time on Regular Expressions this week, though - I don’t think I ever realized it was a whole field of study.

In the mean time, this is an attempt with some explanation (probably not the most elegant, but it seems to work :slight_smile: )

(
a = "
nothing here..
variation1_0;
variation3_0;
variation2_0;
nothing here either.
";
a.findRegexp("variation\\d_\\d").do{ arg match;
	// find start of regex
	var offset = match[0].debug("offset");
	// split found regex at _
	var matchStr = match[1].split($_).debug("matchStr");
	var final;
	// replace last part with "4"
	matchStr[matchStr.size-1] = "4";
	// rejoin 
	final = matchStr.join("_").debug("rejoined");
	// write the rejoined string in a
	a = a.replaceAt(final, offset, final.size);
};
a.postcs;
)

This is not an optimal use of regular expressions, because you still need to do some parsing afterwards (split, etc). It’s easier if to make the regex work for you, parse for exactly what you want, and replace only the portion(s) you want to replace.

By the way, the reason your earlier example didn’t work was because you had no parentheses in your regex, hence no sub-patterns, so each returned match was represented by a single array entry, so doing clump(2) on it made no sense. Also, if you had gotten rid of the clump and done a replace on those overall matches, you would have replaced the whole “variation1_0” string with “4”.

Here is an example for your latest version, using a sub-match on the number after the underscore and just replacing that (in the regex, note the parentheses around the \\d that you want to replace, which will return a submatch):

(
a.findRegexp("variation\\d_(\\d)").clump(2).reverse.do{ arg match;
	var offset = match[1][0], matchStr = match[1][1];
	a = a.replaceAt("4", offset, matchStr.size)
};
a
)