PHP regex replace 'minus' - php

I am trying to remove the 'minus' from a string, but if there are three in sequence I want to keep one.
For example:
today-is---sunny--but-yesterday---it-wasnt
Become:
today is - sunny but yesterday - it wasnt
I was trying to str_replace the - but obviously is removin all of them.
Basicaly I want to remove maximum 2 in sequence.. If there's more keep it.

Not smart enough to make it into one regex so here's 2:
$string = "today-is---sunny--but-yesterday---it-wasnt";
$string = preg_replace("/\b-{1,2}\b/", " ", $string);
$string = preg_replace("/\b-{3,}\b/", " - ", $string);
Seems to work

I would do this in 2 steps using regex.
First, replace the minus symbol with a space if there is 1 or 2 surrounded by word boundries.
preg_replace("/(\b(-){1,2}\b)/", " ", $string);
Pattern (regex101):
word boundry | minus sign (1 or 2) | word boundry
Then, replace all instances of 3 or more minus signs with a minus sign surrounded by spaces.
preg_replace("/(\b(-){3,}\b)/", " - ", $string);
Pattern (regex101):
word boundry | minus sign (3 or more) | word boundry
Note: None of the parenthesis in my example code patterns are required, buet I believe they help readability.
I personally love the way regex101 lays out exactly what is happening in the top right corner of the website with a given pattern, so if you'd like to learn more about how this (or other regex patterns) work, then regex101 is a wonderful resource.

Solution with a callback:
$new = preg_replace_callback(
'/[-]+/',
function ($m) {
return 2 < strlen($m[0])? ' - ' : ' ';
},
'today-is---sunny--but-yesterday---it-wasnt'
);
// today is - sunny but yesterday - it wasnt

Okay, I think this handles the cases mentioned by your updates
$string = "today-is---sunny--but-yesterday---it-wasnt----nothing-----five";
$newstring = preg_replace("/(\-{1,2})(?!\-)/", " ", $string);
$newstring = preg_replace("/(\-+)/", " $1", $newstring);
echo $newstring;
Output is:
today is - sunny but yesterday - it wasnt -- nothing --- five
DEMO
So it matches 1 or 2 dashes that are not followed by a dash and replaces with a space. In the case of more than 2 consecutive dashes, this means it matches only the last 2 in the consecutive string. Then we match a group of 1 or more dashes and precede it with a space.

Do it in three steps:
first replace '/---+/' by '#minus#' (or some other recognisable placeholder)
then replace all /[- ]+/ by ' ' (a single blank)
replace all'#minus#' by ' - '

Just replace all "--" Occurence, and you should get only "-" after that

Have you tried str_replace("---","-",$string)?. This way if there are three minus in sequence, they will be replaced by only one.

Related

How to replace all occurrences of a character except the first one in PHP using a regular expression?

Given an address stored as a single string with newlines delimiting its components like:
1 Street\nCity\nST\n12345
The goal would be to replace all newline characters except the first one with spaces in order to present it like:
1 Street
City ST 12345
I have tried methods like:
[$street, $rest] = explode("\n", $input, 2);
$output = "$street\n" . preg_replace('/\n+/', ' ', $rest);
I have been trying to achieve the same result using a one liner with a regular expression, but could not figure out how.
I would suggest not solving this with complicated regex but keeping it simple like below. You can split the string with a \n, pop out the first split and implode the rest with a space.
<?php
$input = explode("\n","1 Street\nCity\nST\n12345");
$input = array_shift($input) . PHP_EOL . implode(" ", $input);
echo $input;
Online Demo
You could use a regex trick here by reversing the string, and then replacing every occurrence of \n provided that we can lookahead and find at least one other \n:
$input = "1 Street\nCity\nST\n12345";
$output = strrev(preg_replace("/\n(?=.*\n)/", " ", strrev($input)));
echo $output;
This prints:
1 Street
City ST 12345
You can use a lookbehind pattern to ensure that the matching line is preceded with a newline character. Capture the line but not the trailing newline character and replace it with the same line but with a trailing space:
preg_replace('/(?<=\n)(.*)\n/', '$1 ', $input)
Demo: https://onlinephp.io/c/5bd6d
You can use an alternation pattern that matches either the first two lines or a newline character, capture the first two lines without the trailing newline character, and replace the match with what's captured and a space:
preg_replace('/(^.*\n.*)\n|\n/', '$1 ', $input)
Demo: https://onlinephp.io/c/2fb2f
I leave you another method, the regex is correct as long as the conditions are met, in this way it always works
$string=explode("/","1 Street\nCity\nST\n12345");
$string[0]."<br>";
$string[1]." ".$string[2]." ".$string[3]

Regex rules in an array

Maybe it can not be solved this issue as I want, but maybe you can help me guys.
I have a lot of malformed words in the name of my products.
Some of them has leading ( and trailing ) or maybe one of these, it is same for / and " signs.
What I do is that I am explode the name of the product by spaces, and examines these words.
So I want to replace them to nothing. But, a hard drive could be 40GB ATA 3.5" hard drive. I need to process all the word, but I can not use the same method for 3.5" as for () or // because this 3.5" is valid.
So I only need to replace the quotes, when it is at the start of the string AND at end of the string.
$cases = [
'(testone)',
'(testtwo',
'testthree)',
'/otherone/',
'/othertwo',
'otherthree/',
'"anotherone',
'anothertwo"',
'"anotherthree"',
];
$patterns = [
'/^\(/',
'/\)$/',
'~^/~',
'~/$~',
//Here is what I can not imagine, how to add the rule for `"`
];
$result = preg_replace($patterns, '', $cases);
This is works well, but can it be done in one regex_replace()? If yes, somebody can help me out the pattern(s) for the quotes?
Result for quotes should be this:
'"anotherone', //no quote at end leave the leading
'anothertwo"', //no quote at start leave the trailin
'anotherthree', //there are quotes on start and end so remove them.
You may use another approach: rather than define an array of patterns, use one single alternation based regex:
preg_replace('~^[(/]|[/)]$|^"(.*)"$~s', '$1', $s)
See the regex demo
Details:
^[(/] - a literal ( or / at the start of the string
| - or
[/)]$ - a literal ) or / at the end of the string
| - or
^"(.*)"$ - a " at the start of the string, then any 0+ characters (due to /s option, the . matches a linebreak sequence, too) that are captured into Group 1, and " at the end of the string.
The replacement pattern is $1 that is empty when the first 2 alternatives are matched, and contains Group 1 value if the 3rd alternative is matched.
Note: In case you need to replace until no match is found, use a preg_match with preg_replace together (see demo):
$s = '"/some text/"';
$re = '~^[(/]|[/)]$|^"(.*)"$~s';
$tmp = '';
while (preg_match($re, $s) && $tmp != $s) {
$tmp = $s;
$s = preg_replace($re, '$1', $s);
}
echo $s;
This works
preg_replace([[/(]?(.+)[/)]?|/\"(.+)\"/], '$1', $string)

Regular expression currency format with dots and comma

My goal is getting something like that: 150.000,54 or 48.876,05 which means my commas are decimal starters.
Here's my code so far :
<?php
//cut numbers after comma if there are any, after 2 digits
$matchPattern = '/[0-9]+(?:\,[0-9]{2}){0,2}/';
//remove everything except numbers, commas and dots
$repl1 = preg_replace("/[^a-zA-Z0-9,.]/", "", $input);
//let there be a 0 before comma to have values like 0,75
$repl2 = preg_replace("/^[0]{1}$/", "",$repl1);
//now i need you here to help me for the expression putting dots after each 3 numbers, until the comma:
$repl3 = preg_replace("/regexphere$/", ".", $repl2);
preg_match($matchPattern, $repl3, $matches);
echo($matches[0]);
?>
I know preg_replacing 3 times is stupid but I am not good at writing regular expressions. If you have a better idea, don't just share it but also explain. I know a little of the types : http://regexone.com/lesson/0
Thank you in advance.
--------UPDATE--------
So I need to handle 0000,45 like inputs to 0,45 and like 010101,84 inputs to 1,84
When this is done, I'm done.
$input = Input::get('userinput');
$repl1 = preg_replace("/[^0-9,.]/", "", $input);
$repl2 = preg_replace("/^0/", "",$repl1);
$repl3 = str_replace(".","",$repl2);
preg_match('/[0-9]+(?:\,[0-9]{2}){0,2}/', $repl3, $matches);
$repl4 = preg_replace('/(\d)(?=(\d{3})+(?!\d))/', '$1.', $matches[0]);
return repl4;
----UPDATE----
Here's what i get so far : https://ideone.com/5qmslB
I just need to remove the zeroes before the comma, before the numbers.
I am not sure this is the best way, but I hope it is helpful.
Here is the updated code that I used with a fake $input:
<?php
$input = "textmdwrhfejhg../,2222233333,34erw.re.ty";
//cut numbers after comma if there are any, after 2 digits
$matchPattern = '/[0-9]+(?:\,[0-9]{2}){0,2}/';
//remove everything except numbers, commas and dots
$repl1 = trim(preg_replace("/[^0-9,.]/", "", $input), ".,");
echo "$repl1" . "\n";
//let there be a 0 before comma to have values like 0,75, remove the 0
$repl2 = preg_replace("/^0/", "",$repl1);
echo "$repl2" . "\n";
//The expression putting dots after each 3 numbers, until the comma:
$repl3 = preg_replace('/(\d)(?=(?:\d{3})+(?!\d))/', '$1.', $repl2);
echo "$repl3" . "\n";
The expression putting dots after each 3 numbers is
(\d)(?=(?:\d{3})+(?!\d))
Here, you can see how it works. In plain human,
(\d) - A capturing group that we'll use in the replacement pattern, matching a single digit that....
(?=(?:\d{3})+(?!\d)) - is followed by groups of 3 digits. External (?=...) is a look-ahead construction that checks but does not consume characters, (?:\d{3})+ is a non-capturing group (no need to keep the matched text in memory) that matches 3 digits exactly (due to the limiting quantifier {3}) 1 or more times (due to the + quantifier), and (?!\d) is a negative look-ahead checking that the next character after the last matched 3-digit group is not a digit.
This does not work in case we have more than 3 digits after a decimal separator. With regex, I can only think of a way to support 4 digits after decimal with (?<!,)(\d)(?=(?:\d{3})+(?!\d)). Not sure if there is a generic way without variable-width look-behind in PHP (as here, we also need a variable-width look-ahead, too). Thus, you might consider splitting the $repl2 value by comma, and only pass the first part to the regex. Then, combine. Something like this:
$spl = split(',', $repl2); // $repl2 is 1234,123456
$repl3 = preg_replace('/(\d)(?=(?:\d{3})+(?!\d))/', '$1.', $spl[0]);
$repl3 .= "," . $spl[1]; // "1.234" + "," + "123456"
echo "$repl3" . "\n"; // 1.234,123456
Update:
The final code I have come up with:
$input = "textmdwrhfejhg../0005456,2222233333,34erw.re.ty";
//Here's mine :
$repl1 = trim(preg_replace("/[^0-9,.]/", "", $input), '.,');
//following line just removes one zero, i want it to remove all chars like
//Input : 000549,569 Output : 549,569
echo "$repl1\n";
$repl2 = preg_replace("/^0+(?!,)/", "",$repl1);
$repl3 = str_replace(".","",$repl2);
preg_match('/[0-9]+(?:\,[0-9]{2}){0,2}/', $repl3, $matches);
$repl4 = preg_replace('/(\d)(?=(\d{3})+(?!\d))/', '$1.', $matches[0]);
echo $repl4;

REGEX - php preg_replace :

How to replace part of a string based on a "." (period) character
only if it appears after/before/between a word(s),
not when it is before/between any number(s).
Example:
This is a text string.
-Should be able to replace the "string." with "string ."
(note the Space between the end of the word and the period)
Example 2
This is another text string. 2.0 times longer.
-Should be able to replace "string." with "string ."
(note the Space between the end of the word and the period)
-Should Not replace "2.0" with "2 . 0"
It should only do the replacement if the "." appears at the end/start of a word.
Yes - I've tried various bits of regex.
But everything I do results in either nothing happening,
or the numbers are fine, but I take the last letter from the word preceeding the "."
(thus instead of "string." I end up with "strin g.")
Yes - I've looked through numerous posts here - I have seen Nothing that deals with the desire, nor the "strange" problem of grabbing the char before the ".".
You can use a lookbehind (?<=REXP)
preg_replace("/(?<=[a-z])\./i", "XXX", "2.0 test. abc") // <- "2.0 testXXX abc"
which will only match if the text before matches the corresponding regex (in this case [a-z]). You may use a lookahead (?=REXP) in the same way to test text after the match.
Note: There is also a negative lookbehind (?<!REXP) and a negative lookahead (?!REXP) available which will reject matches if the REXP does not match before or after.
$input = "This is another text string. 2.0 times longer.";
echo preg_replace("/(^\.|\s\.|\.\s|\.$)/", " $1", $input);
http://ideone.com/xJQzQ
I'm not too good with the regex, but this is what I would do to accomplish the task with basic PHP. Basically explode the entire string by it's . values, look at each variable to see if the last character is a letter or number and add a space if it's a number, then puts the variable back together.
<?
$string = "This is another text string. 2.0 times longer.";
print("$string<br>");
$string = explode(".",$string);
$stringcount = count($string);
for($i=0;$i<$stringcount;$i++){
if(is_numeric(substr($string[$i],-1))){
$string[$i] = $string[$i] . " ";
}
}
$newstring = implode('.',$string);
print("$newstring<br>");
?>
It should only do the replacement if the "." appears at the end/start of a word.
search: /([a-z](?=\.)|\.(?=[a-z]))/
replace: "$1 "
modifiers: ig (case insensitive, globally)
Test in Perl:
use strict;
use warnings;
my $samp = '
This is another text string. 2.0 times longer.
I may get a string of "this and that.that and this.this 2.34 then that 78.01."
';
$samp =~ s/([a-z](?=\.)|\.(?=[a-z]))/$1 /ig;
print "$samp";
Input:
This is another text string. 2.0 times longer.
I may get a string of "this and that.that and this.this 2.34 then that 78.01."
Output:
This is another text string . 2.0 times longer .
I may get a string of "this and that . that and this . this 2.34 then that 78.01."

Replace the leading space with with the same number of times using a PHP regular expression

I want to replace leading space with with the same number of occurrences.
Explanation:
If one leading space exist in the input then it should replace it with one .
If two leading spaces exist in input then it should replace with two s.
If n leading spaces are exist in the input then it should replace it with exactly n number of times with .
Example 1:
My name is XYZ
Output:
My name is XYZ
Example 2:
My name is XYZ
Output:
My name is XYZ
How can I replace only leading spaces, using a PHP regular expression?
preg_replace('/\G /', ' ', $str);
\G matches the position where the last match ended, or the beginning of the string if there isn't any previous match.
Actually, in PHP it matches where the next match is supposed to begin. That isn't necessarily the same as where the previous match ended.
$len_before = strlen($str);
$str = ltrim($str, ' ');
$len_after = strlen($str);
$str = str_repeat(' ', $len_before - $len_after) . $str;
Using preg_replace there is also
$str = preg_replace('/^( +)/e', 'str_repeat(" ", strlen("$1"))', $str);
but note that it uses the /e flag.
See http://www.ideone.com/VWNKZ for the result.
Use:
preg_replace('/^ +/m', ' ', $str);
You can test it here.
Use preg_match with PREG_OFFSET_CAPTURE flag set. The offset is the length of the "spaces". Then use str_repeat with the offset.

Categories