2

I'm trying to find the right regexp to do the following:

input: '$MM.Player.Panning(1, 0.1)'; output '$MM->Player->Panning(1, 0.1)';

I can't figure out how to replace the dots with '->', without replacing dots between the round braces.

Any input or suggestions would be highly appreciated

Peter Elzinga
  • 125
  • 3
  • 15
  • Note: all kinds of data is passed between the round braces, included json-strings, which may contain strings themselves. – Peter Elzinga Feb 09 '12 at 15:25

3 Answers3

1

One suggestion is: (since you are likely to pass numbers in the parenthesis and the dots outside are surrounded by non numbers)

Try (\D)\.(\D) and replace with $1->$2

sudipto
  • 2,472
  • 1
  • 17
  • 21
  • @Peter Elzinga That only works if the `.` you want to keep are in numbers. Are you sure it's what you want? Also: be careful, it won't work with `Panning(1, 0.)`. – SteeveDroz Feb 09 '12 at 15:05
  • 1
    That did the trick... can't get this with regexp generators... ** needs to learn regexp when time available ** Thnks – Peter Elzinga Feb 09 '12 at 15:12
  • @Oltarus other function do require json-strings containing strings, so there could be a possibility that user inputted strings contain dots. Have you got a better solution to prevent errors due to invalid input? – Peter Elzinga Feb 09 '12 at 15:29
  • 1
    @Oltarus; i pulled apart the two parts: the function and the arguments part. Then i use the regexp as Sudimail gave me to replace the dots, after which i put the two parts back together: `preg_match('/(\\().*(\\))/', $string, $matches, PREG_OFFSET_CAPTURE); $func = substr($string, 0, $matches[0][1]); $func = preg_replace('/(\D)\.(\D)/', '$1->$2', $func); $string = $func.$matches[0][0];` – Peter Elzinga Feb 09 '12 at 15:50
  • @Oltarus if you got a simpler, smaller solution i would still like to know – Peter Elzinga Feb 09 '12 at 15:53
1

The best solution would be not to use regexp.

Try a small function that parses your string like that:

(Function in PHP, I don't know what language you're using)

function dotReplacer($string) {
  $parenthesis = 0; // Counts if we are inside parenthesis or not.
  $listOfDots = array(); // List of the index of the $string which contain dots to replace.
  $listOfElements = array(); // List of elements between these dots. e.g.: $MM, Player and Panning(1, 0.1)
  $newString = ''; // The new string to return.
  for ($i = 0; $i < strlen($string); $i++) { // Check with every character in the $string...
    switch (substr($string, $i, 1)) {
      case '(':
        $parenthesis++; // If we see an opening parenthesis, increase the level.
      break;

      case ')':
        $parenthesis--; // If we see a closing parenthesis, decrease the level.
      break;

      case '.':
        if ($parenthesis == 0) {
          $listOfDots[] = $i; // If we see a dot AND we are not inside parenthesis, include the character index in the list to replace.
        }
      break;

      default:
    }
  }

  $iterator = 0; // Beginning at the start of the string...
  foreach ($listOfDots as $dot) {
    $listOfElements[] = substr($string, $iterator, $dot - $iterator); // Add the element that is between the iterator and the next dot.
    $iterator = $dot + 1; // Move the iterator after the dot.
  }
  $listOfElements[] = substr($string, $iterator); // Do that one more time for everything that takes place after the last dot.
  return implode('->', $listOfElements); // Return an imploded list of elements with '->' between the elements.
}

It works perfectly, I tried. Your input and output are correct.

SteeveDroz
  • 6,006
  • 6
  • 33
  • 65
  • Hey Oltarus. Why shouldn't i use regexp and use your script, while your script is a lot more complex? – Peter Elzinga Feb 11 '12 at 17:02
  • Because the regexp doesn't work in every case. My script does. Now if you use a very precise syntax, for instance you only need to recognize decimal points, use the regexp. My script also works for strings like `gpd.ar(gfo.ffe).p2v` → `gpd->ar(gfo.ffe)->p2v`. It's really up to you, I simply gave a complete answer of what you asked… I had fun creating that script, which may be my main goal in the process. – SteeveDroz Feb 12 '12 at 10:46
  • aha thats made it clear. But my solution is sufficient in my case, so i'll just use that ;) – Peter Elzinga Feb 12 '12 at 18:55
0

Peter, you said:

if you got a simpler, smaller solution i would still like to know

Would much simpler and smaller be okay? :)

Here is the whole solution:

$regex = '~\([^)]*\)(*SKIP)(*F)|(\.)~';
$subject = '$MM.Player.Panning(1, 0.1)';
$replaced = preg_replace($regex,"->",$subject);

Your situation is straight out of Match (or replace) a pattern except in situations s1, s2, s3 etc. We use this simple regex:

\([^)]*\)(*SKIP)(*F)|\.

The left side of the alternation matches complete (parenthesized expressions) then deliberately fails and skips that part of the string. The right side matches dots, and we know they are the right dots because they were not matched by the expression on the left.

These are the dots we need to replace. You can see the results at the bottom of the online demo.

Reference

How to match (or replace) a pattern except in situations s1, s2, s3...

Community
  • 1
  • 1
zx81
  • 41,100
  • 9
  • 89
  • 105