Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing based on position in string

Tags:

regex

php

Is there a way using regex to replace characters in a string based on position?

For instance, one of my rewrite rules for a project I’m working on is “replace o with ö if o is the next-to-last vowel and even numbered (counting left to right).”

So, for example:

  • heabatoik would become heabatöik (o is the next-to-last vowel, as well as the fourth vowel)
  • habatoik would not change (o is the next-to-last vowel, but is the third vowel)

Is this possible using preg_replace in PHP?

like image 926
Chris Avatar asked Feb 01 '10 15:02

Chris


People also ask

How do you replace a character in a string in Java at a specific position?

String are immutable in Java. You can't change them. You need to create a new string with the character replaced.

How do you replace a string in a specific position in C++?

To change a specific character in a string to another value, we refer to the index number position of the character in the string and use single quotation marks ( ' ' ). To access a character of a string in C++, we simply specify the index position of the character in the string in square brackets [] .


2 Answers

Starting with the beginning of the subject string, you want to match 2n + 1 vowels followed by an o, but only if the o is followed by exactly one more vowel:

$str = preg_replace(
  '/^((?:(?:[^aeiou]*[aeiou]){2})*)' .  # 2n vowels, n >= 0
    '([^aeiou]*[aeiou][^aeiou]*)' .     # odd-numbered vowel
    'o' .                               # even-numbered vowel is o
    '(?=[^aeiou]*[aeiou][^aeiou]*$)/',  # exactly one more vowel
  '$1$2ö',
  'heaeafesebatoik');

To do the same but for an odd-numbered o, match 2n leading vowels rather than 2n + 1:

$str = preg_replace(
  '/^((?:(?:[^aeiou]*[aeiou]){2})*)' .  # 2n vowels, n >= 0
    '([^aeiou]*)' .                     # followed by non-vowels
    'o' .                               # odd-numbered vowel is o
    '(?=[^aeiou]*[aeiou][^aeiou]*$)/',  # exactly one more vowel
  '$1$2ö',
  'habatoik');

If one doesn't match, then it performs no replacement, so it's safe to run them in sequence if that's what you're trying to do.

like image 60
Greg Bacon Avatar answered Nov 03 '22 00:11

Greg Bacon


You can use preg_match_all to split the string into vowel/non-vowel parts and process that.

e.g. something like

preg_match_all("/(([aeiou])|([^aeiou]+)*/",
    $in,
    $out, PREG_PATTERN_ORDER);

Depending on your specific needs, you may need to modify the placement of ()*+? in the regex.

like image 44
David Schmitt Avatar answered Nov 03 '22 00:11

David Schmitt