I have data in this format coming from a database...
BUS 101S Business and Society
or
BUS 101 Business and Society
Notice the optional "S" character (which can be any uppercase character)
I need to replace the "BUS 101S" part with null and here is what I have come up with...
$value = "BUS 101S Business and Society";
$sub = substr($value, 0, 3); // Gives me "BUS"
$num = substr($value, 4, 3); // Gives me "101"
$new_value = preg_replace("/$sub $num"."[A-Z]?/", null, $value);
The value of $new_value now contains S Business and Society. So I'm close, Just need it to replace the optional single uppercase character as well. Any ideas?
Assuming the pattern is 3 uppercase letters, 3 numbers and then an optional uppercase letter, just use a single preg_match:
$new = preg_replace('/^[A-Z]{3} \d{3}[A-Z]?/', '', $old);
The ^ will only match at the beginning of a line/string. The {3} means "match the preceding token 3 times exactly". The ? means "match the preceding token zero or one times"
You can also do something like this, so you don't bother with substr:
preg_replace('#^[A-Z]{3} [0-9]{3}[A-Z]? (.*)$#', '$1', $value);
Or using preg_match, to get all the components of the string
if (preg_match('#^([A-Z]{3}) ([0-9]{3})([A-Z]?) (.*)$#', $value, $matches)) {
$firstMatch=$matches[1];//BUS ($matches[0] is the whole string)
$secondMatch=$matches[2];//101
$secondMatch=$matches[3];//S or ''
$secondMatch=$matches[4];//the rest of the text
}
Wouldn't it just be easier to do something like:
$str = 'BUS 101S Business and Society';
$words = explode(' ', $str);
array_unshift($words); // bus
array_unshift($words); // 101s
$str = implode(' ', $words);
Related
I want to split a space-delimited string by its spaces, but I need the total elements in the result array to be exactly 3 AND if the string has more than two spaces, only the last two spaces should be used as delimiters.
My input strings follow a predictable format. The strings are one or more words, then a word, then a parenthetically wrapped word (word in this context is a substring with no whitespaces in it).
Sample strings:
Stack Over Flow Abcpqr (UR)becomes:["Stack Over Flow", "Abcpqr", "(UR)"]
Fluency in English Conversation Defklmno (1WIR)becomes:["Fluency in English Conversation","Defklmno","(1WIR)"]
English Proficiency GHI (2WIR)becomes:["English Proficiency","GHI","(2WIR)"]
Testing ADG (3WIR)becomes:["Testing","ADG","(3WIR)"]
I used the following code, but it is only good for Testing (3WIR).
$Original = $row['fld_example'];
$OriginalExplode = explode(' ', $Original);
<input name="example0" id="example0" value="<?php echo $OriginalExplode[0]; ?>" type="text" autocomplete="off" required>
<input name="example1" id="example1" value="<?php echo $OriginalExplode[1]; ?>" type="text" autocomplete="off" required>
Basically, I just need to explode the string on spaces, starting from the end of the string, and limiting the total explosions to 2 (to make 3 elements.
You can approach this using explode and str_replace
$string = "Testing (3WIR)";
$stringToArray = explode(":",str_replace("(",":(",$string));
echo '<pre>';
print_r($stringToArray);
Edited question answer:-
$subject = "Fluency in English Conversation Defklmno (1WIR)";
$toArray = explode(' ',$subject);
if(count($toArray) > 2){
$first = implode(" ",array_slice($toArray, 0,count($toArray)-2));
$second = $toArray[count($toArray)-2];
$third = $toArray[count($toArray)-1];
$result = array_values(array_filter([$first, $second, $third]));
}else{
$result = array_values(array_filter(explode(":",str_replace("(",":(",$subject))));
}
DEMO HERE
I am not a fan of regular expressions, but this one seems to work very fine:
Regex to split a string only by the last whitespace character
So the PHP code would be:
function splitAtLastWord($sentence)
{
return preg_split("/\s+(?=\S*+$)/", $sentence);
}
$sentence = "Fluency in English Conversation Defklmno (1WIR)";
list($begin, $end) = splitAtLastWord($sentence);
list($first, $middle) = splitAtLastWord($begin);
$result = [$first, $middle, $end];
echo "<pre>" . print_r($result, TRUE) . "</pre>";
The output is:
Array
(
[0] => Fluency in English Conversation
[1] => Defklmno
[2] => (1WIR)
)
You can also write the same function without a regular expression:
function splitAtLastWord($sentence)
{
$words = explode(" ", $sentence);
$last = array_pop($words);
return [implode(" ", $words), $last];
}
Which is, to be honest, a better way of doing this.
This is a computationally more efficient way to do it:
function splitAtLastWord($sentence)
{
$lastSpacePos = strrpos($sentence, " ");
return [substr($sentence, 0, $lastSpacePos), substr($sentence, $lastSpacePos + 1)];
}
It looks a bit less nice but it is faster.
Anyway, defining a separate function like this is useful, you can reuse it in other places.
To isolate the two delimiting spaces, use / (?=(?:\S+ )?\()/ which leverages a lookahead containing an optional group.
Code: (Demo)
$strings = [
'Stack Over Flow Abcpqr (UR)',
'Fluency in English Conversation Defklmno (1WIR)',
'English Proficiency GHI (2WIR)',
'Testing ADG (3WIR)',
];
foreach ($strings as $string) {
echo json_encode(
preg_split('/ (?=(?:\S+ )?\()/', $string)
) . "\n";
}
Output:
["Stack Over Flow","Abcpqr","(UR)"]
["Fluency in English Conversation","Defklmno","(1WIR)"]
["English Proficiency","GHI","(2WIR)"]
["Testing","ADG","(3WIR)"]
Pattern Breakdown:
#match a literal space
(?= #start lookahead
(?:\S+ )? #optionally match one or more non-whitespaces followed by a space
\( #match a literal opening parenthesis
) #end lookahead
When matching the first delimiting space, the optional subpattern will match characters. When matching the second delimiting space (before the parenthesis), the optional subpattern will not match any characters.
As a more generic solution, if the goal was to split on the space before either of the last two non-whitespace substrings, this pattern looks ahead in the same fashion but matches all the way to the end of the string.
/ (?=(?:\S+ )?\S+$)/
While I don't find non-regex solutions to be anywhere near as elegant or concise, here is one way to explode on all spaced then implode all elements except the last two: (Demo)
function implodeNotLastTwoElements($string) {
$array = explode(' ', $string);
array_splice($array, 0, -2, implode(' ', array_slice($array, 0, -2)));
return $array;
}
foreach ($strings as $string) {
echo json_encode(implodeNotLastTwoElements($string)) . "\n";
}
Or (Demo)
function implodeNotLastTwoElements($string) {
$array = explode(' ', $string);
return [implode(' ', array_slice($array, 0, -2))] + array_slice($array, -3);
}
These non-regex approaches are iterating/scanning over the data 4 times versus regex only scanning the input string once and directly creating the desired result. The decision between regex or non-regex is a no-brainer for me in this case.
I am trying to something like this.
Hiding users except for first 3 characters.
EX)
apple -> app**
google -> goo***
abc12345 ->abc*****
I am currently using php like this:
$string = "abcd1234";
$regex = '/(?<=^(.{3}))(.*)$/';
$replacement = '*';
$changed = preg_replace($regex,$replacement,$string);
echo $changed;
and the result be like:
abc*
But I want to make a replacement to every single character except for first 3 - like:
abc*****
How should I do?
Don't use regex, use substr_replace:
$var = "abcdef";
$charToKeep = 3;
echo strlen($var) > $charToKeep ? substr_replace($var, str_repeat ( '*' , strlen($var) - $charToKeep), $charToKeep) : $var;
Keep in mind that regex are good for matching patterns in string, but there is a lot of functions already designed for string manipulation.
Will output:
abc***
Try this function. You can specify how much chars should be visible and which character should be used as mask:
$string = "abcd1234";
echo hideCharacters($string, 3, "*");
function hideCharacters($string, $visibleCharactersCount, $mask)
{
if(strlen($string) < $visibleCharactersCount)
return $string;
$part = substr($string, 0, $visibleCharactersCount);
return str_pad($part, strlen($string), $mask, STR_PAD_RIGHT);
}
Output:
abc*****
Your regex matches all symbols after the first 3, thus, you replace them with a one hard-coded *.
You can use
'~(^.{3}|(?!^)\G)\K.~'
And replace with *. See the regex demo
This regex matches the first 3 characters (with ^.{3}) or the end of the previous successful match or start of the string (with (?!^)\G), and then omits the characters matched from the match value (with \K) and matches any character but a newline with ..
See IDEONE demo
$re = '~(^.{3}|(?!^)\G)\K.~';
$strs = array("aa","apple", "google", "abc12345", "asdddd");
foreach ($strs as $s) {
$result = preg_replace($re, "*", $s);
echo $result . PHP_EOL;
}
Another possible solution is to concatenate the first three characters with a string of * repeated the correct number of times:
$text = substr($string, 0, 3).str_repeat('*', max(0, strlen($string) - 3));
The usage of max() is needed to avoid str_repeat() issue a warning when it receives a negative argument. This situation happens when the length of $string is less than 3.
I have original data like this
Original Data:
SRI ISTYANINGSIH
DIANA WREDHININGSIH
ENDANG WAHYU PURWANINGSIH
THERESIA PUDJI ASTUTIE SARI
And I need to show it like this:
View Data:
SRI I.
DIANA W.
ENDANG W. P.
THERESIA P. A. S.
How can I accomplish this using PHP and regular expressions?
This is a simple solution which could easily be turned into a function.
$name = 'THERESIA PUDJI ASTUTIE SARI';
//split the name to a maximum of 2 array values.
list ($first_name, $second_names) = explode(' ', $name, 2);
$second_names = explode(' ', $second_names);
foreach ($second_names as $key => $value) {
$second_names[$key] = $value[0] . '.';
}
echo $first_name . ' ' . implode(' ', $second_names);
suppose, $var has the string that you want to convert.
$var = "THERESIA PUDJI ASTUTIE SARI";
$parts = explode(" ", $var);
$str = $parts[0]." ";
for($i=1; $i<count($parts); $i++){
$str .= $parts[$i][0].". ";
}
echo $str will give you desired output.
I don't know what you mean with "make delimiter" but here is a regular expression based solution:
function shorten_name($name) {
return preg_replace('/ (\w)\w*/', ' $1.', $name);
}
The pattern matches a space followed by any number of "word characters" (\w), i.e. letters (locale aware), digits and underscores, then replaces this sequence with only the space, the first letter and a dot.
Possible modifications:
If you only want to match uppercase letters from A-Z like in your example, replace \w with [A-Z].
If you want to match anything that is not a space (i.e. "MÜLLER-RIEBENSEE" => "M."), replace \w with \S (non-whitespace).
If you want to have other characters than the space as separator, use character class and subpattern for it too for example: preg_replace('/([\s-])(\w)\w*/', '$1$2.', $name) to take any whitespace character \s or the dash - as separator (i.e. "MÜLLER-RIEBENSEE" => "M.-R.")
I have a string Trade Card Catalogue 1988 Edition I wish to remove everything apart from 1988.
I could have an array of all letters and do a str_replace and trim, but I wondered if this was a better solution?
$string = 'Trade Card Catalogue 1988 Edition';
$letters = array('a','b','c'....'x','y','z');
$string = str_to_lower($string);
$string = str_replace($letters, '', $string);
$string = trim($string);
Thanks in advance
Regular expression?
So assuming you want the number (and not the 4th word or something like that):
$str = preg_replace('#\D#', '', $str);
\D means every character that is not a digit. The same as [^0-9].
If there could be more numbers but you only want to get a four digit number (a year), this will also work (but obviously fails if you there are several four digit numbers and you want to get a specific one) :
$str = preg_replace('#.*?(\d{4,4}).*#', '\1', $str);
You can actually just pass the entire set of characters to be trimmed as a parameter to trim:
$string = trim($string, 'abc...zABC...Z ' /* don't forget the space */);
I'm trying build a regex that will replace any characters not of the format:
any number of digits, then optional (single decimal point, any number of digits)
i.e.
123 // 123
123.123 // 123.123
123.123.123a // 123.123123
123a.123 // 123.123
I am using ereg_replace in php and the closest to a working regex i have managed is
ereg_replace("[^.0-9]+", "", $data);
which is almost what i need (apart from it will allow any number of decimal points)
i.e.
123.123.123a // 123.123.123
my next attempt was
ereg_replace("[^0-9]+([^.]?[^0-9]+)?", "", $data);
which was meant to translate as
[^0-9]+ // any number of digits, followed by
( // start of optional segment
[^.]? // decimal point (0 or 1 times) followed by
[^0-9]+ // any number of digits
) // end of optional segment
? // optional segment to occur 0 or 1 times
but this just seems to allow any number of digits and nothing else.
Please help
Thanks
Try these steps:
remove any character except 0-9 and .
remove any . behind the first decimal point.
Here’s a implementation with regular expressions:
$str = preg_replace('/[^0-9.]+/', '', $str);
$str = preg_replace('/^([0-9]*\.)(.*)/e', '"$1".str_replace(".", "", "$2")', $str);
$val = floatval($str);
And another one with just one regular expression:
$str = preg_replace('/[^0-9.]+/', '', $str);
if (($pos = strpos($str, '.')) !== false) {
$str = substr($str, 0, $pos+1).str_replace('.', '', substr($str, $pos+1));
}
$val = floatval($str);
This should be faster, actually. And it is way more readable. ;-)
$s = preg_replace('/[^.0-9]/', '', '123.123a.123');
if (1 < substr_count($s, '.')) {
$a = explode('.', $s);
$s = array_shift($a) . '.' . implode('', $a);
}