Splitting a string using lookback in PHP - php

I have a product feed where the product options is formatted like this:
Color{1} : Black[14], White[42] Size{2} : Small[16], Medium[17], Large[18]
For my script to understand and parse the product options correctly, it needs to be in the following format:
Color:Black,White|Size:Small,Medium,Large
I started out like this to remove unnecessary information:
$matches[1] = preg_replace("/\{\d{1,}\} : /", ': ', $matches[1]);
$matches[1] = preg_replace("/\[\d{1,}\]/", '', $matches[1]);
Which gives this output:
Color: Black, White Size: Small, Medium, Large
But my problem now is "how to insert a pipe before the option name, unless its only one option, or the first option". I guess I need to use some sort of lookback, but I have no idea.

First, split the string into several individual options using preg_split():
$arr = preg_split('/\s+(?=[a-z]+{\d+})/i', $str);
(?=[a-z]+{\d+}) is a positive lookahead that asserts that the whitespace (\s+) is followed by a string of the format <string>{xx}. It's used here to pinpoint on which spaces the split should happen. It's important to note that the lookahead assertion is zero-width, i.e. it doesn't consume any characters at all.
Once you have the split array, loop through it, and remove {xx}, [xx] parts and whitespace:
foreach ($arr as &$str)
$str = preg_replace('/(?:{\d+}|\[\d+\]|\s*)/', '', $str);
Join the array by |:
echo join('|', $arr);
Output:
Color:Black,White|Size:Small,Medium,Large
Demo

This method uses only two iterations of regex substitution
First, delete all spaces along with digits
$re = "/(.\\d+.|[ ]+)/";
$str = "Color{1} : Black[14], White[42] Size{2} : Small[16], Medium[17], Large[18]";
$subst = '';
$result = preg_replace($re, $subst, $str);
Then add in the pipe
$re = "/([a-z])([A-Z])/";
$subst = '\1|\2';
$endresult = preg_replace($re, $subst, $result);
Input:
Color{1} : Black[14], White[42] Size{2} : Small[16], Medium[17], Large[18]
Output:
Color:Black,White|Size:Small,Medium,Large
Here's a quick demo
Note: I'm assuming that the digits are always surrounded by a curly brace or a bracket without any spacing in between and that the quantity names are only alpha character (never digits).

Related

Php make spaces in a word with a dash

I have the following string:
$thetextstring = "jjfnj 948"
At the end I want to have:
echo $thetextstring; // should print jjf-nj948
So basically what am trying to do is to join the separated string then separate the first 3 letters with a -.
So far I have
$string = trim(preg_replace('/s+/', ' ', $thetextstring));
$result = explode(" ", $thetextstring);
$newstring = implode('', $result);
print_r($newstring);
I have been able to join the words, but how do I add the separator after the first 3 letters?
Use a regex with preg_replace function, this would be a one-liner:
^.{3}\K([^\s]*) *
Breakdown:
^ # Assert start of string
.{3} # Match 3 characters
\K # Reset match
([^\s]*) * # Capture everything up to space character(s) then try to match them
PHP code:
echo preg_replace('~^.{3}\K([^\s]*) *~', '-$1', 'jjfnj 948');
PHP live demo
Without knowing more about how your strings can vary, this is working solution for your task:
Pattern:
~([a-z]{2}) ~ // 2 letters (contained in capture group1) followed by a space
Replace:
-$1
Demo Link
Code: (Demo)
$thetextstring = "jjfnj 948";
echo preg_replace('~([a-z]{2}) ~','-$1',$thetextstring);
Output:
jjf-nj948
Note this pattern can easily be expanded to include characters beyond lowercase letters that precede the space. ~(\S{2}) ~
You can use str_replace to remove the unwanted space:
$newString = str_replace(' ', '', $thetextstring);
$newString:
jjfnj948
And then preg_replace to put in the dash:
$final = preg_replace('/^([a-z]{3})/', '\1-', $newString);
The meaning of this regex instruction is:
from the beginning of the line: ^
capture three a-z characters: ([a-z]{3})
replace this match with itself followed by a dash: \1-
$final:
jjf-nj948
$thetextstring = "jjfnj 948";
// replace all spaces with nothing
$thetextstring = str_replace(" ", "", $thetextstring);
// insert a dash after the third character
$thetextstring = substr_replace($thetextstring, "-", 3, 0);
echo $thetextstring;
This gives the requested jjf-nj948
You proceeding is correct. For the last step, which consists in inserting a - after the third character, you can use the substr_replace function as follows:
$thetextstring = 'jjfnj 948';
$string = trim(preg_replace('/\s+/', ' ', $thetextstring));
$result = explode(' ', $thetextstring);
$newstring = substr_replace(implode('', $result), '-', 3, false);
If you are confident enough that your string will always have the same format (characters followed by a whitespace followed by numbers), you can also reduce your computations and simplify your code as follows:
$thetextstring = 'jjfnj 948';
$newstring = substr_replace(str_replace(' ', '', $thetextstring), '-', 3, false);
Visit this link for a working demo.
Oldschool without regex
$test = "jjfnj 948";
$test = str_replace(" ", "", $test); // strip all spaces from string
echo substr($test, 0, 3)."-".substr($test, 3); // isolate first three chars, add hyphen, and concat all characters after the first three

Operation on string in PHP. Remove part of string

How can i remove part of string from example:
##lang_eng_begin##test##lang_eng_end##
##lang_fr_begin##school##lang_fr_end##
##lang_esp_begin##test33##lang_esp_end##
I always want to pull middle of string: test, school, test33. from this string.
I Read about ltrim, substr and other but I had no good ideas how to do this. Becouse each of strings can have other length for example :
'eng', 'fr'
I just want have string from middle between ## and ##. to Maye someone can help me? I tried:
foreach ($article as $art) {
$title = $art->titl = str_replace("##lang_eng_begin##", "", $art->title);
$art->cleanTitle = str_replace("##lang_eng_end##", "", $title);
}
But there
##lang_eng_end##
can be changed to
##lang_ger_end##
in next row so i ahvent idea how to fix that
If your strings are always in this format, an explode way looks easy:
$str = "##lang_eng_begin##test##lang_eng_end## ";
$res = explode("##", $str)[2];
echo $res;
You may use a regex and extract the value in between the non-starting ## and next ##:
$re = "/(?!^)##(.*?)##/";
$str = "##lang_eng_begin##test##lang_eng_end## ";
preg_match($re, $str, $match);
print_r($match[1]);
See the PHP demo. Here, the regex matches a ## that is not at the string start ((?!^)##), then captures into Group 1 any 0+ chars other than newline as few as possible ((.*?)) up to the first ## substring.
Or, replace all ##...## substrings with `preg_replace:
$re = "/##.*?##/";
$str = "##lang_eng_begin##test##lang_eng_end## ";
echo preg_replace($re, "", $str);
See another demo. Here, we just remove all non-overlapping substrings beginning with ##, then having any 0+ chars other than a newline up to the first ##.

How to not perform preg_replace if subject starts with quote

I'm trying to convert plain links to HTML links using preg_replace. However it's replacing links that are already converted.
To combat this I'd like it to ignore the replacement if the link starts with a quote.
I think a positive lookahead may be needed but everything I've tried hasn't worked.
$string = 'test http://www.example.com';
$string = preg_replace("/((https?:\/\/[\w]+[^ \,\"\n\r\t<]*))/is", "$1", $string);
var_dump($string);
The above outputs:
http://www.example.com">test</a> http://www.example.com
When it should output:
test http://www.example.com
You might get along with lookarounds.
Lookarounds are zero-width assertions that make sure to match/not to match anything immediately around the string in question. They do not consume any characters.
That being said, a negative lookbehind might be what you need in your situation:
(?<![">])\bhttps?://\S+\b
In PHP this would be:
<?php
$string = 'I want to be transformed to a proper link: http://www.google.com ';
$string .= 'But please leave me alone ';
$string .= '(https://www.google.com).';
$regex = '~ # delimiter
(?<![">]) # a neg. lookbehind
https?://\S+ # http:// or https:// followed by not a whitespace
\b # a word boundary
~x'; # verbose to enable this explanation.
$string = preg_replace($regex, "<a href='$0'>$0</a>", $string);
echo $string;
?>
See a demo on ideone.com. However, maybe a parser is more appropriate.
Since you can use Arrays in preg_replace, this might be convenient to use depending on what you want to achieve:
<?php
$string = 'test http://www.example.com';
$rx = array("&(<a.+https?:\/\/[\w]+[^ \,\"\n\r\t<]*>)(.*)(<\/a\>)&si", "&(\s){1,}(https?:\/\/[\w]+[^ \,\"\n\r\t<]*)&");
$rp = array("$1$2$3", "$2");
$string = preg_replace($rx,$rp, $string);
var_dump($string);
// DUMPS:
// 'testhttp://www.example.com'
The Idea
You can split your string at the already existing anchors, and only parse the pieces in between.
The Code
$input = 'test http://www.example.com';
// Split the string at existing anchors
// PREG_SPLIT_DELIM_CAPTURE flag includes the delimiters in the results set
$parts = preg_split('/(<a.*?>.*?<\/a>)/is', $input, PREG_SPLIT_DELIM_CAPTURE);
// Use array_map to parse each piece, and then join all pieces together
$output = join(array_map(function ($key, $part) {
// Because we return the delimiter in the results set,
// every $part with an uneven key is an anchor.
return $key % 2
? preg_replace("/((https?:\/\/[\w]+[^ \,\"\n\r\t<]*))/is", "$1", $part)
: $part;
}, array_keys($parts), $parts);

PHP Replace consecutive occurrence of characters in sentence

I want to replace all consecutive characters in each WORD if there are more than three (three being the most possible in German language, two for English so I know the output example is grammatically wrong).
Example input:
Hellooooo Louis, whaaaaaat's up pal?
Expected output:
Hellooo Louis, whaaat's up pal?
I tried to change:
preg_replace('/(\w)\1+/', '$1', $word);
to
preg_replace('/(\w)\3+/', '$1', $word);
However, it doesn't output anything.
You can use the following regex:
((\w)\2{2})\2+
See demo
Replace with $1.
IDEONE:
$re = "#((\w)\\2{2})\\2+#";
$str = "Hellooooo Louis, whaaaaaat's up pal?";
$subst = "$1";
$result = preg_replace($re, $subst, $str);
echo $result;
Output:
Hellooo Louis, whaaat's up pal?
EXPLANATION:
We capture the symbol with (\w) - it is Group 2 value. Then, we check if it is followed by the same character with \2{2} exactly 2 times, and we capture it into Group 1. Then, we match any more identical subsequent characters with the \2 backreference.
Here is a way to go:
preg_replace('/((\w)\2\2)\2+/', '$1', $word);
Also you can use \K for resetting after and replace with empty, which is a bit more efficient:
(\w)\1\1\K\1+
See regex101

Explode string by one or more spaces or tabs

How can I explode a string by one or more spaces or tabs?
Example:
A B C D
I want to make this an array.
$parts = preg_split('/\s+/', $str);
To separate by tabs:
$comp = preg_split("/\t+/", $var);
To separate by spaces/tabs/newlines:
$comp = preg_split('/\s+/', $var);
To seperate by spaces alone:
$comp = preg_split('/ +/', $var);
This works:
$string = 'A B C D';
$arr = preg_split('/\s+/', $string);
The author asked for explode, to you can use explode like this
$resultArray = explode("\t", $inputString);
Note: you must used double quote, not single.
I think you want preg_split:
$input = "A B C D";
$words = preg_split('/\s+/', $input);
var_dump($words);
instead of using explode, try preg_split: http://www.php.net/manual/en/function.preg-split.php
In order to account for full width space such as
full width
you can extend Bens answer to this:
$searchValues = preg_split("#[\s+ ]#u", $searchString);
Sources:
strip out multi-byte white space from a string PHP
What are all the Japanese whitespace characters?
(I don't have enough reputation to post a comment, so I'm wrote this as an answer.)
Assuming $string = "\tA\t B \tC \t D "; (a mix of tabs and spaces including leading tab and trailing space)
Obviously splitting on just spaces or just tabs will not work. Don't use these:
preg_split('~ +~', $string) // one or more literal spaces, allow empty elements
preg_split('~ +~', $string, -1, PREG_SPLIT_NO_EMPTY) // one or more literal spaces, deny empty elements
preg_split('~\t+~', $string) // one or more tabs, allow empty elements
preg_split('~\t+~', $string, -1, PREG_SPLIT_NO_EMPTY) // one or more tabs, deny empty elements
Use these:
preg_split('~\s+~', $string) // one or more whitespace character, allow empty elements
preg_split('~\s+~', $string, -1, PREG_SPLIT_NO_EMPTY), // one or more whitespace character, deny empty elements
preg_split('~[\t ]+~', $string) // one or more tabs or spaces, allow empty elements
preg_split('~[\t ]+~', $string, -1, PREG_SPLIT_NO_EMPTY) // one or more tabs or spaces, allow empty elements
preg_split('~\h+~', $string) // one or more horizontal whitespaces, allow empty elements
preg_split('~\h+~', $string, -1, PREG_SPLIT_NO_EMPTY) // one or more horizontal whitespaces, deny empty elements
A demonstration of all techniques below can be found here.
Reference Horizontal Whitespace

Categories