Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #38085 > unrolled thread

regex replaceAll?

Started byEric Douglas <e.d.programmer@gmail.com>
First post2018-03-01 06:19 -0800
Last post2018-03-02 02:25 +0100
Articles 9 on this page of 29 — 5 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-01 06:19 -0800
    Re: regex replaceAll? Andreas Leitgeb <avl@logic.at> - 2018-03-01 19:03 +0000
      Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-01 12:15 -0800
        Re: regex replaceAll? Daniele Futtorovic <da.futt.news@laposte.net> - 2018-03-01 21:51 +0100
          Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-01 13:36 -0800
            Re: regex replaceAll? Arne Vajhøj <arne@vajhoej.dk> - 2018-03-01 16:59 -0500
        Re: regex replaceAll? Andreas Leitgeb <avl@logic.at> - 2018-03-01 21:55 +0000
          Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-01 14:00 -0800
            Re: regex replaceAll? Andreas Leitgeb <avl@logic.at> - 2018-03-01 22:31 +0000
              Re: regex replaceAll? Arne Vajhøj <arne@vajhoej.dk> - 2018-03-01 17:52 -0500
                Re: regex replaceAll? Andreas Leitgeb <avl@logic.at> - 2018-03-02 00:14 +0000
              Re: regex replaceAll? Kiwi User <martin@mydomain.invalid> - 2018-03-02 00:43 +0000
                Re: regex replaceAll? Arne Vajhøj <arne@vajhoej.dk> - 2018-03-01 19:49 -0500
                  Re: regex replaceAll? Kiwi User <martin@mydomain.invalid> - 2018-03-02 01:33 +0000
                    Re: regex replaceAll? Arne Vajhøj <arne@vajhoej.dk> - 2018-03-02 13:00 -0500
                      Re: regex replaceAll? Kiwi User <martin@mydomain.invalid> - 2018-03-03 20:07 +0000
              Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-02 05:40 -0800
                Re: regex replaceAll? Andreas Leitgeb <avl@logic.at> - 2018-03-02 17:46 +0000
                  Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-02 10:38 -0800
                    Re: regex replaceAll? Andreas Leitgeb <avl@logic.at> - 2018-03-02 20:15 +0000
                      Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-02 12:43 -0800
                      Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-02 12:58 -0800
                        Re: regex replaceAll? Daniele Futtorovic <da.futt.news@laposte.net> - 2018-03-03 00:06 +0100
    Re: regex replaceAll? Daniele Futtorovic <da.futt.news@laposte.net> - 2018-03-01 20:29 +0100
      Re: regex replaceAll? Daniele Futtorovic <da.futt.news@laposte.net> - 2018-03-01 20:30 +0100
      Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-01 12:28 -0800
        Re: regex replaceAll? Daniele Futtorovic <da.futt.news@laposte.net> - 2018-03-01 21:40 +0100
      Re: regex replaceAll? Eric Douglas <e.d.programmer@gmail.com> - 2018-03-01 13:52 -0800
        Re: regex replaceAll? Daniele Futtorovic <da.futt.news@laposte.net> - 2018-03-02 02:25 +0100

Page 2 of 2 — ← Prev page 1 [2]


#38111

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-03-02 12:43 -0800
Message-ID<2faf552c-1197-4937-88ea-fcf3e2a33034@googlegroups.com>
In reply to#38110
On Friday, March 2, 2018 at 3:16:02 PM UTC-5, Andreas Leitgeb wrote:
> It really seems to me now as if Java (1.8.0_131 here) was just buggy here:
> 
> "abaabaaabaaaabaaaaabaaaaaabxbb".replaceAll( "(?<=\G[^b]*b[^b]*b[^b]*)b", "_");
> 
> works, while
> 
> "abaabaaabaaaabaaaaabaaaaaabxbb".replaceAll( "(?<=\G[^b]*b[^b]*)b", "_");
> 
> doesn't.
> 
> The apparent "pattern" is, that adding "b[^b]*" will alternate between
> working and not working.
> 
> Using {2} in a (?<=...) doesn't seem to work at all --
>   "Look-behind group does not have an obvious maximum length ..."
> 

Is that so?  That may be what started the confusion...

> Anyway:
> 
>    out = in.replaceAll( "([^b]*b[^b]*)[b]" , "$1_");
> 
> seems to work just fine, and:
> 
>    out = in.replaceAll( "([^b]*(b[^b]*){2})b" , "$1_");
> 
> only replaces every third b.
> 

Sounds like we're onto something here.
My test string:
String in = "abc aa bb cc a bb ccc   a b c abc aa bbb cc babacaca";
Code found on internet:
String out;
   out = in.replaceAll("(?<=\\G\\S*\\s\\S*\\s\\S*)\\s", "_");
Seems to work, with test string having separated and adjacent whitespace characters.  result:
"abc aa bb_cc a bb_ccc  _a b c_abc aa bbb_cc babacaca"
New expression:
   out = in.replaceAll("([^b]*b[^b]*)b", "$1_");
Now gives expected result, including the $1 which was somehow not needed in the first expression.
"abc aa _b cc a _b ccc   a _ c abc aa _b_ cc ba_acaca"
Your second suggestion also appears to be working perfectly with the {1} removing every other, {2} removing every 3rd, {3} removing every 4th occurrence..

> Imho, that's one STRONG argument for the simpler approach.
> 

Simpler depends on point of view.  The regex approach is a single line of code using only Oracle Java API, while the other approach does require creating a method somewhere in a custom API.

> >> Well, nope.  if you do a "ababab".replaceAll("b","_"); you'd
> >> want all "b"s replaced, even if not adjacent to the previous
> >> one.
> > Maybe it's just me, but "end of previous" was not clear.
> > If you're search the "ababab" string and you're looking for "bab"
> > can it find it twice?
> 
> Nope, but in  "babababa", if you search for \\Gbab you'll get only 
> one match, because the second match is not adjacent to the first one.
> 
> Without the \\G, the next match *may* still start adjacent ("babbab"),
> but *may* also start later ("babxyzbab").
> 
> Under no circumstances(*) will the second match overlap a previous one.
> 
> *: except, of course, when Java's RE impl is buggy. Then all bets are off.

I think that makes sense, still not clear why the ?<=\\G makes the whitespace replace work, and leaves the other characters intact without requiring the $1.

[toc] | [prev] | [next] | [standalone]


#38112

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-03-02 12:58 -0800
Message-ID<a134f5ee-80b0-4539-b636-7ac6796a1ef5@googlegroups.com>
In reply to#38110
On Friday, March 2, 2018 at 3:16:02 PM UTC-5, Andreas Leitgeb wrote:
> 
> *: except, of course, when Java's RE impl is buggy. Then all bets are off.

Unless I'm missing something, replaceAll does appear to be buggy.
I started with this.
     String in = "abc aa bb cc a bb ccc   a b c abc aa bbb cc babacaca";
     String out;
Then I tried to make this new regex dynamic.
     out = in.replaceAll( "([^"+match+"]*("+match+"[^"+match+"]*){"+(n-1)+"})"+match, "$1"+rep);
I add more complex parameters.
     int n = 2;
     String match = "bb";
     String rep = "_";
I get expected result.
"abc aa bb cc a _ ccc   a b c abc aa bbb cc babacaca"
I change the parameter:
     int n = 3;
Now the regex gets this result:
"abc aa bb cc a bb ccc   a b c abc aa bbb cc babacaca"
While the custom method Daniele wrote gets this expected result:
"abc aa bb cc a bb ccc   a b c abc aa _b cc babacaca"
At least it works for every single character replacement I've tested.

[toc] | [prev] | [next] | [standalone]


#38113

FromDaniele Futtorovic <da.futt.news@laposte.net>
Date2018-03-03 00:06 +0100
Message-ID<p7cld9$uqk$1@dont-email.me>
In reply to#38112
On 2018-03-02 21:58, Eric Douglas wrote:
> On Friday, March 2, 2018 at 3:16:02 PM UTC-5, Andreas Leitgeb wrote:
>>
>> *: except, of course, when Java's RE impl is buggy. Then all bets are off.
> 
> Unless I'm missing something, replaceAll does appear to be buggy.
> I started with this.
>      String in = "abc aa bb cc a bb ccc   a b c abc aa bbb cc babacaca";
>      String out;
> Then I tried to make this new regex dynamic.
>      out = in.replaceAll( "([^"+match+"]*("+match+"[^"+match+"]*){"+(n-1)+"})"+match, "$1"+rep);
> I add more complex parameters.
>      int n = 2;
>      String match = "bb";
>      String rep = "_";
> I get expected result.
> "abc aa bb cc a _ ccc   a b c abc aa bbb cc babacaca"
> I change the parameter:
>      int n = 3;
> Now the regex gets this result:
> "abc aa bb cc a bb ccc   a b c abc aa bbb cc babacaca"
> While the custom method Daniele wrote gets this expected result:
> "abc aa bb cc a bb ccc   a b c abc aa _b cc babacaca"
> At least it works for every single character replacement I've tested.

Using character classes will work if you're trying to match a single
character -- not if there are more. "[^bb]" doesn't do what you seem to
think it does. It's equivalent to "[^b]" (again, these are character
classes, not negated matches).

-- 
DF.

[toc] | [prev] | [next] | [standalone]


#38088

FromDaniele Futtorovic <da.futt.news@laposte.net>
Date2018-03-01 20:29 +0100
Message-ID<p79ka7$enj$1@dont-email.me>
In reply to#38085
On 2018-03-01 15:19, Eric Douglas wrote:
> I hate to ask because I feel like I'm close and missing something stupid, but how do you do this?

Do what?

> <snip />

> Now I'm trying to replace the nth occurrence of a string.

^This?

Here's one way:
    public static CharSequence replaceEveryNthOccurrenceOf(
        CharSequence input, String match, int nthMatch, String replaceWith
    )
    {
        if( nthMatch <= 0 ){
            throw new IllegalArgumentException("nthMatch must be positive");
        }

        Pattern p = Pattern.compile( match );
        Matcher m = p.matcher( input );
        StringBuffer sb = new StringBuffer();
        boolean found = true;
        do {
            for( int ii = nthMatch; ii --> 0 && (found = m.find()); ){
                m.appendReplacement( sb, ii == 0 ? replaceWith : "$0" );
            }
        }
        while( found );

        m.appendTail( sb );

        return sb;
    }

Note also: how to replace every nth _consecutive_ occurrence of String
(regex) "match" in the input "input" with replacement "rep":
        String input, match, rep;
        int n;
        input.replaceAll( "((?:" + match + "){" + (n - 1) + "})(" +
match + ")", "$1" + rep );

HTH,

-- 
DF.
> The best I can find matches the nth sequential.
> 
> int n = 2;
> String repl = "b";
>  out = in.replaceAll("([.]*["+repl+"]{"+(n-1)+"}[.]*)"+repl,"$1_");
> System.out.println(out);
> 
> Result:
> "abc aa b_ cc a b_ ccc   a b c abc aa b_b cc babacaca"
> 
> What I'm looking for:
> "abc aa _b cc a _b ccc   a _ c abc aa _b_ cc ba_acaca"
> 

[toc] | [prev] | [next] | [standalone]


#38089

FromDaniele Futtorovic <da.futt.news@laposte.net>
Date2018-03-01 20:30 +0100
Message-ID<p79kdo$enj$2@dont-email.me>
In reply to#38088
On 2018-03-01 20:29, Daniele Futtorovic wrote:
> Note also: how to replace every nth _consecutive_ occurrence of String
> (regex) "match" in the input "input" with replacement "rep":
>         String input, match, rep;
>         int n;
>         input.replaceAll( "((?:" + match + "){" + (n - 1) + "})(" +
> match + ")", "$1" + rep );

Oh, you already got that part. My bad, got lost a bit.

-- 
DF.

[toc] | [prev] | [next] | [standalone]


#38091

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-03-01 12:28 -0800
Message-ID<66e1310d-f709-4501-ba68-467e7c424392@googlegroups.com>
In reply to#38088
On Thursday, March 1, 2018 at 2:29:24 PM UTC-5, Daniele Futtorovic wrote:
> > Now I'm trying to replace the nth occurrence of a string.
> 
> ^This?
> 
> Here's one way:
>     public static CharSequence replaceEveryNthOccurrenceOf(
>         CharSequence input, String match, int nthMatch, String replaceWith
>     )
>     {
>         if( nthMatch <= 0 ){
>             throw new IllegalArgumentException("nthMatch must be positive");
>         }
> 
>         Pattern p = Pattern.compile( match );
>         Matcher m = p.matcher( input );
>         StringBuffer sb = new StringBuffer();
>         boolean found = true;
>         do {
>             for( int ii = nthMatch; ii --> 0 && (found = m.find()); ){
>                 m.appendReplacement( sb, ii == 0 ? replaceWith : "$0" );
>             }
>         }
>         while( found );
> 
>         m.appendTail( sb );
> 
>         return sb;
>     }
> 

I could easily write a search/replace loop method.  I've been trying to figure out how to do it with a single method, as in the replaceAll, or possibly a lamba?, but I did get the replaceAll that somehow seems to work for blank spaces.

> Note also: how to replace every nth _consecutive_ occurrence of String
> (regex) "match" in the input "input" with replacement "rep":
>         String input, match, rep;
>         int n;
>         input.replaceAll( "((?:" + match + "){" + (n - 1) + "})(" +
> match + ")", "$1" + rep );
> 
> HTH,
> 
> -- 
> DF.

Pretty sure I tried exactly that, or something close enough.  It gets this result.

abc aa b_ cc a b_ ccc   a b c abc aa b_b cc babacaca

Replacing every search character only if it occurs twice back to back.
I was hoping to find all search character and replace every 2nd one, ignoring the rest of the string.
search string "ssdfsdfsdfsdfsdfsdfsdf"
search character "s"
replace character "."
result "s.dfsdf.dfsdf.dfsdf.df"

One area I'd like to use that is to line format a collection display.  The toString lists the elements comma delimited.  I want to call a method that replaces all the commas with linefeeds, or every other comma, or every third comma, depending on the size of the elements and the size of my display area for the result.  Otherwise the best I get is a run-on string that can wrap so a lot of the elements get split and it's rather hard to read.

[toc] | [prev] | [next] | [standalone]


#38092

FromDaniele Futtorovic <da.futt.news@laposte.net>
Date2018-03-01 21:40 +0100
Message-ID<p79ogf$gs2$1@dont-email.me>
In reply to#38091
On 2018-03-01 21:28, Eric Douglas wrote:
> I could easily write a search/replace loop method.  I've been trying to figure out how to do it with a single method, as in the replaceAll, or possibly a lamba?, but I did get the replaceAll that somehow seems to work for blank spaces.

You could also set yourself the goal of writing it in ASM. Not sure that
would get you anywhere fast, either.

> One area I'd like to use that is to line format a collection display.  The toString lists the elements comma delimited.  

Stream<String>#collect( Collectors.joining(...) )

[toc] | [prev] | [next] | [standalone]


#38095

FromEric Douglas <e.d.programmer@gmail.com>
Date2018-03-01 13:52 -0800
Message-ID<071d7ec0-3a09-42e1-a4c7-2a99331a65c9@googlegroups.com>
In reply to#38088
On Thursday, March 1, 2018 at 2:29:24 PM UTC-5, Daniele Futtorovic wrote:
> > Now I'm trying to replace the nth occurrence of a string.
> 
> ^This?
> 
> Here's one way:
>     public static CharSequence replaceEveryNthOccurrenceOf(
>         CharSequence input, String match, int nthMatch, String replaceWith
>     )
>     {
>         if( nthMatch <= 0 ){
>             throw new IllegalArgumentException("nthMatch must be positive");
>         }
> 
>         Pattern p = Pattern.compile( match );
>         Matcher m = p.matcher( input );
>         StringBuffer sb = new StringBuffer();
>         boolean found = true;
>         do {
>             for( int ii = nthMatch; ii --> 0 && (found = m.find()); ){
>                 m.appendReplacement( sb, ii == 0 ? replaceWith : "$0" );
>             }
>         }
>         while( found );
> 
>         m.appendTail( sb );
> 
>         return sb;
>     }

That is the long way, to be re-usable I have to put that in a custom method to call, not sure why I can't get this to work with the single replaceAll statement but this is the logic I'm looking for.

"abc aa bb cc a bb ccc   a b c abc aa bbb cc babacaca"
search for "b", replace every 2nd with "_" results in
"abc aa _b cc a _b ccc   a _ c abc aa _b_ cc ba_acaca"

[toc] | [prev] | [next] | [standalone]


#38104

FromDaniele Futtorovic <da.futt.news@laposte.net>
Date2018-03-02 02:25 +0100
Message-ID<p7a96h$v69$1@dont-email.me>
In reply to#38095
On 2018-03-01 22:52, Eric Douglas wrote:
> On Thursday, March 1, 2018 at 2:29:24 PM UTC-5, Daniele Futtorovic wrote:
>>> Now I'm trying to replace the nth occurrence of a string.
>>
>> ^This?
>>
>> Here's one way:
>>     public static CharSequence replaceEveryNthOccurrenceOf(
>>         CharSequence input, String match, int nthMatch, String replaceWith
>>     )
>>     {
>>         if( nthMatch <= 0 ){
>>             throw new IllegalArgumentException("nthMatch must be positive");
>>         }
>>
>>         Pattern p = Pattern.compile( match );
>>         Matcher m = p.matcher( input );
>>         StringBuffer sb = new StringBuffer();
>>         boolean found = true;
>>         do {
>>             for( int ii = nthMatch; ii --> 0 && (found = m.find()); ){
>>                 m.appendReplacement( sb, ii == 0 ? replaceWith : "$0" );
>>             }
>>         }
>>         while( found );
>>
>>         m.appendTail( sb );
>>
>>         return sb;
>>     }
> 
> That is the long way, to be re-usable I have to put that in a custom method to call, not sure why I can't get this to work with the single replaceAll statement but this is the logic I'm looking for.

Because regexes are not a multi-tool, like a scripting language; they're
the very opposite, a highly specialised tool. As such, as soon as you
step out of their speciality (like, I would argue, in this case), they
cease to be a boon and become a burden.

Maybe you'll manage to get it to work like you want if you just try long
and hard enough (it's by no means a given). Or you could take my word
for it: you'll either get stuck, or end up with something horribly
convoluted and impractical. And I'm pretty certain everyone else here
will tell you the same thing. Because we've been there, done that,
bumped our heads against the wall, and gotten out a tidbit wiser. That
approach you're taking to regexes is precisely the origin of, and the
nugget of truth in, the saying (mentioned elsethreads) that if you have
a problem, and you try to solve it using regexes, you end up with two
problems.

-- 
DF.

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.java.programmer


csiph-web