string modifier function

I need to modify a series of strings containing e.g.

_123abc
__abc123
___abcxyz
xzy789_
_123abc_
789123___

to become e.g.:

_ 123abc
__ abc123
___ abcxyz
xzy789 _
_ 123abc _
789123 ___

So each last underscore on the front of the middle needs a space if it has one and on the end of the middle bit a space before the underscore if an underscore is there. If there is no underscore then no space is added.

I can do this using an inelegant for loop although there must be a better way.

I tried using preg_replace ereg_replace although the syntax isn't documented well enough for me to use it.


LVL 7
evcrAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

SteveH_UKCommented:
Assuming a string is in $val, try:

$val = preg_replace('/^(_+)([^ ])/', '${1} ${2}', $val);
$val = preg_replace('/([^ ])(_+)$/', '${1} ${2}', $val);

or:

$patterns[0] = '/^(_+)([^ ])/';
$patterns[1] = '/([^ ])(_+)$/';
$reps[0] = '${1} ${2}';
$reps[1] = '${1} ${2}';
$val = preg_replace($patterns, $reps, $val);

0
evcrAuthor Commented:


Thanks that works fine although I forgot a bit....

each string has an associated string e.g.

a 123abc
bb abc123
ccc abcxyz
xzy789 1
z 123abc z
789123 cc

so I need to add the spaces in the same place as the strings with underscores...


0
SteveH_UKCommented:
The trick here is to define the pattern.

In these cases you would have:

'/(123abc)$/' --> ' ${1}'
'/(abc123)$/' --> ' ${1}'
'/(abcxyz)$/' --> ' ${1}'
'/^(xzy789)/' --> '${1} '
'/(.)(123abc)(.)/' --> '${1} ${2} ${3}'
'/^(789123)/' --> '${1} '

All of these can be placed in the patterns and reps arrays I previously suggested.  However, depending on the actual content of your strings you may need more sophisticated expressions to prevent one string matching more than once.  Also, if you intend the matching to be more general, you will need to use character sets such as:

[0-9]  or \d = a decimal digit
[a-zA-Z]  = alphabetic character

For the first test, for example:

'/^([a-zA-Z])([0-9][0-9][0-9][a-zA-Z][a-zA-Z][a-zA-Z])$/' --> '${1} ${2}'

which can be simplified to:

'/^([a-zA-Z])(\d{3}[a-zA-Z]{3})$/'  --> '${1} ${2}'

The {3} means match the previous character (or group or character set) exactly three times.
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

evcrAuthor Commented:

yeah, thanks but I only know where to put the spaces based on where the underscores appear, e.g. if i have two arrays:

$arr1 = ['_123abc','__abc123','___abcxyz','xzy789_',_123abc_,'789123___'];

$arr1 = ['a123abc','123abc123','zx3abcxyz','xzy789z',a123abcz,'789123ab3'];

The result would need to be e.g.:

$arr1 = ['a 123abc','123 abc123','zx3 abcxyz','xzy789 z',a 123abc z,'789123 ab3'];

I couldn't see a way to get the positions of the underscores using regex, I realise using substr() in a for loop would work although it seems the wrong way to do it.


0
evcrAuthor Commented:
oops the second $arr1 is supposed to be $arr2
0
SteveH_UKCommented:
You could do it as follows:

1.  Loop through your arrays
2.  Construct patterns and replacements based on $arr1 using preg_match
3.  Use preg_replace using the patterns, replacements and the contents of $arr2

So...

$result = array();

foreach ($arr1 as $index => $a1) {
  $matches = array();
  preg_match('/^(_*)?([0-9A-Za-z]+)(_*)?$/', $a1, $matches);

  $len_p1 = strlen($matches[1]);
  $len_p2 = strlen($matches[2]);
  $len_p3 = strlen($matches[3]);
  $i = 1;
  $pattern = '/^';
  $replace = '';

  if ($len_p1 > 0) {
    $pattern .= '([A-Za-z0-9]{' . $len_p1 . '})';
    $replace .= '${' . $i . '} ';
    $i++;
  }
    $pattern .= '([A-Za-z0-9]{' . $len_p2 . '})';
    $replace .= '${' . $i . '}';
    $i++;
  if ($len_p3 > 0) {
    $pattern .= '([A-Za-z0-9]{' . $len_p3 . '})';
    $replace .= ' ${' . $i . '}';
    $i++;
  }
  $pattern .= '$/';

  $result[] = preg_replace($pattern, $replace, $arr2[$index]);
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
evcrAuthor Commented:

works a treat, thanks Steve.

0
SteveH_UKCommented:
You're welcome.  Glad we got it working for you :)

Do you understand the logic, or would you like me to explain it further?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.