Cut (crop) some text in a string - php

I have a string with 3 block parameters (words, digits, slashes) and i need to separate it and print only last block parameters. I do this:
<?php
$howmuch="17шт / 119ml / 255грн";
echo preg_replace("/(\\d\\w\\ / )(\\d\\w\\ / )(\\d\\w\\ / )$/i", "$3", $howmuch);
?>
I need to print only 255грн, but my script do nothing. Please help me to fix a problem. Thank you to all.

If the format is fixed, you may get the value without any regex using
explode(" / ", $howmuch)[2]
See the PHP demo. It will split the string with space-/-space and get you the third element of the resulting array.
Alternatively, you may extract a number with грн after it using a preg_match operation (this approach lets you find the match regardless of how many / there are before or after the match):
$howmuch="17шт / 119ml / 255грн";
if (preg_match("/\d+\s*грн/ui", $howmuch, $results)) {
echo $results[0];
}
See the PHP demo.
If the value can contain a fractional part, you may use "/\d+(?:[.,]\d+)?\s*грн/ui" where (?:[.,]\d+)? matches an optional sequence of a . or , followed with 1+ digits.

Why not keep it simple and understandable, for instance, like this:
$howMuch = '17шт / 119ml / 255грн';
$blocks = explode('/',$howMuch);
echo $blocks[2];
This doesn't need much explaining, or working out why it does what it does.

All regex free options:
echo explode('/', $howMuch)[2];
if you need to ensure string has three sections
if (substr_count($howmuch, '/') > 1) {
echo explode('/', $howMuch)[2];
}
if you are on a php version prior to 5.4
$chunks = explode('/', $howMuch);
echo $chunks[2];

Related

php - Get string before nth dash (-)

I have a string that looks something like this:
abc-def-ghi-jkl-mno-pqr-stu-vwx-yz I'd like to get the content BEFORE the 4th dash, so effectively, I'd like to get abc-def-ghi-jkl assigned to a new string, then I'd like to get mno assigned to a different string.
How could I go about doing this? I tried using explode but that changed it to an array and I didn't want to do it that way.
Try this:
$n = 4; //nth dash
$str = 'abc-def-ghi-jkl-mno-pqr-stu-vwx-yz';
$pieces = explode('-', $str);
$part1 = implode('-', array_slice($pieces, 0, $n));
$part2 = $pieces[$n];
echo $part1; //abc-def-ghi-jkl
echo $part2; //mno
See demo
http://php.net/manual/en/function.array-slice.php
http://php.net/manual/en/function.explode.php
http://php.net/manual/en/function.implode.php
Can you add your source code? I done this one before but I cant remember the exact source code I used. But I am pretty sure I used explode and you can't avoid using array.
EDIT: Mark M answer is right.
you could try using substr as another possible solution
http://php.net/manual/en/function.substr.php
If I see where you are trying to get with this you could also go onto substr_replace
I guess an alternative to explode would be to find the position of the 4th - in the string and then get a substring from the start of the string up to that character.
You can find the position using a loop with the method explained at find the second occurrence of a char in a string php and then use substr(string,0,pos) to get the substring.
$string = "abc-def-ghi-jkl-mno-pqr-stu-vwx-yz";
$pos = -1;
for($i=0;$i<4;$i++)
$pos = strpos($string, '-', $pos+1);
echo substr($string, 0, $pos);
Code isn't tested but the process is easy to understand. You start at the first character (0), find a - and on the next loop you start at that position +1. The loop repeats it for a set number of times and then you get the substring from the start to that last - you found.

If second to last character is numeric

I would like to figure out, how to check if the second to last character of a string is numeric.
My string is:
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
The URL is something like: http://www.domain.com/2/,http://www.domain.com/3/ and so on..
Is it possible to figure out if a number exists at the end of the URL before the last back slash / ?
Something like:
if (is_numeric($url, second-to-last-character)) {
// Do real stuff
} else {
// Do whatever
}
What about regexes ?
if (!preg_match('#/\d+/?$#', $url))
// There is no numeric at the end, abort !
I propose this because you won't know how many digits your id will have, so you can't just test the second-to-last character.
$fullurl = explode('/',$_SERVER['SCRIPT_NAME']);
$last = $fullurl[count($fullurl)-1];
//echo $last;
if(is_int($last))
echo "integer";
else
echo "Not integer";
You want to use substr. You can use this to get the second to last character.
http://php.net/manual/en/function.substr.php
is_numeric(substr($url, -2, 1);
if (is_numeric(substr($url, -2,1) ) {
should do you, You dont need the regex
use substr
if(is_numeric(substr($url,-2,1))){
//dosomething
}else{
echo "Invalid URL!";
}
in substr, the first parameter is the string, the second one is the offset, if the offset is negative, it will start at the end and go backwards, and the last one is the length. If not specified, it will go to the end of the string. So if you wanted to get the last tow characters, you would do substr($url,-2)
$url='http://www.domain.com/2/,http://www.domain.com/3/';
if(is_numeric (substr($url,-2,1))){
echo "This is number";
}else{
echo "This is not number";
}
I don't want to get offtopic, but when i'm dealing with URLs usually i delete ending slashes using
$url = rtrim($url, '/');
http://www.php.net/manual/en/function.rtrim.php
Usually you won't need that slash and it'll be messy when exploding the URL. You can use the substr() function as mentioned by previous answers to get the last character of the string then. AFAIK the substr() function is faster than using regular expressions for such a simple task.
if (is_numeric(substr($url, -1)) {}
edit
i just realized that if you are dealing with values > 9 you will be in trouble.
Better get the whole number as mentioned in another answer. If you prefer strange looking code with slightly better performance you can use that one instead of explode():
$value = strrev(strtok(strrev($url), '/'));
if (is_numeric($value)) {}

Removing content from start and end of string (PHP)

I'm trying to get a users ID from a string such as:
http://www.abcxyz.com/123456789/
To appear as 123456789 essentially stripping the info up to the first / and also removing the end /. I did have a look around on the net but there seems to be so many solutions but nothing answering both start and end.
Thanks :)
Update 1
The link can take two forms: mod_rewrite as above and also "http://www.abcxyz.com/profile?user_id=123456789"
I would use parse_url() to cleanly extract the path component from the URL:
$path = parse_URL("http://www.example.com/123456789/", PHP_URL_PATH);
and then split the path into its elements using explode():
$path = trim($path, "/"); // Remove starting and trailing slashes
$path_exploded = explode("/", $path);
and then output the first component of the path:
echo $path_exploded[0]; // Will output 123456789
this method will work in edge cases like
http://www.example.com/123456789?test
http://www.example.com//123456789
www.example.com/123456789/abcdef
and even
/123456789/abcdef
$string = 'http://www.abcxyz.com/123456789/';
$parts = array_filter(explode('/', $string));
$id = array_pop($parts);
If the ID always is the last member of the URL
$url="http://www.abcxyz.com/123456789/";
$id=preg_replace(",.*/([0-9]+)/$,","\\1",$url);
echo $id;
If there is no other numbers in the URL, you can also do
echo filter_var('http://www.abcxyz.com/123456789/', FILTER_SANITIZE_NUMBER_INT);
to strip out everything that is not a digit.
That might be somewhat quicker than using the parse_url+parse_str combination.
If your domain does not contain any numbers, you can handle both situations (with or without user_id) using:
<?php
$string1 = 'http://www.abcxyz.com/123456789/';
$string2 = 'http://www.abcxyz.com/profile?user_id=123456789';
preg_match('/[0-9]+/',$string1,$matches);
print_r($matches[0]);
preg_match('/[0-9]+/',$string2,$matches);
print_r($matches[0]);
?>

Preg_match for a date

I am trying to match a date in PHP using preg_match, split it and assign parts of it to an array, the date looks like "20100930", here is the code I am using:
// Make the tor_from date look nicer
$nice_from = $_POST['tor_from'];
$matches = array();
$ideal_from = '';
preg_match('/\d{4}\\d{2}\\d{2}\/', $nice_from, $matches, PREG_OFFSET_CAPTURE, 0);
// if (isset($matches[0])) $nice_from = $matches[0];
echo $matches[0];
echo "<br />";
echo $matches[1];
echo "<br />";
echo $matches[2];
echo "<br />";
echo $matches[3];
echo "<br />";
Ive been using:
http://php.net/manual/en/function.preg-match.php and PHP preg_match question to formulate ideas on how to do this, however I have had no luck in getting it to work. Any help would be greatly appreciated.
Although regex isn't really a good solution for parsing a date in YYYYMMDD format, let's walk through why your pattern isn't working.
Your pattern \d{4}\\d{2}\\d{2}\ says: "match 4 digits (\d{4}), followed by a backslash character (\\), followed by the letter d twice (d{2}), followed by another backslash (\\) and then finally another two d's (d{2})."
As you might have figure out by now, you don't want the double slashes!
\d{4}\d{2}\d{2}
Will match 4 digits, followed by 2 digits, and then another 2 digits.
Furthermore, you are not specifying any capturing groups, so your subpatterns will never be filled. What you probably meant was:
(\d{4})(\d{2})(\d{2})
See this in action at http://www.ideone.com/iAy7K. Note that there really isn't any reason in your case to be specifying the PREG_OFFSET_CAPTURE flag (which returns the position of each match) or 0 for the offset.
Forget preg_match, use strtotime():
echo date('Y/m/d', strtotime($_POST['tor_from']));
It's better like this, using preg_match and indexed names.
$res = preg_match("/(?P<year>[0-9]{4})(?P<month>[0-9]{2})(?P<day>[0-9]{2})/", $date, $matches);
And Matches will look like:,
array('year' => 2010, 'month' => 12, 'day' => 07);
Cheers.
Regex is not the best way to go here if the pattern is this simple. Use substr instead:
$date = '20100930';
$year = substr($date,0,4);
$month = substr($date,4,2);
$day = substr($date,6,2);
You need to put some parenthesis around the patterns that you would like to show up in $matches. Also i don't think you want the double \\ in between your \d's because that will escape the second \ and leave you matching a literal 'd'.

Regular Expressions: how to do "option split" replaces

those reqular expressions drive me crazy. I'm stuck with this one:
test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not
Task:
Remove all [[ and ]] and if there is an option split choose the later one so output should be:
test1:link test2:silver test3:out1insideout2 test4:this|not
I came up with (PHP)
$text = preg_replace("/\\[\\[|\\]\\]/",'',$text); // remove [[ or ]]
this works for part1 of the task. but before that I think I should do the option split, my best solution:
$text = preg_replace("/\\[\\[(.*\|)(.*?)\\]\\]/",'$2',$text);
Result:
test1:silver test3:[[out1[[inside]]out2]] this|not
I'm stuck. may someone with some free minutes help me? Thanks!
I think the easiest way to do this would be multiple passes. Use a regular expression like:
\[\[(?:[^\[\]]*\|)?([^\[\]]+)\]\]
This will replace option strings to give you the last option from the group. If you run it repeatedly until it no longer matches, you should get the right result (the first pass will replace [[out1[[inside]]out2]] with [[out1insideout2]] and the second will ditch the brackets.
Edit 1: By way of explanation,
\[\[ # Opening [[
(?: # A non-matching group (we don't want this bit)
[^\[\]] # Non-bracket characters
* # Zero or more of anything but [
\| # A literal '|' character representing the end of the discarded options
)? # This group is optional: if there is only one option, it won't be present
( # The group we're actually interested in ($1)
[^\[\]] # All the non-bracket characters
+ # Must be at least one
) # End of $1
\]\] # End of the grouping.
Edit 2: Changed expression to ignore ']' as well as '[' (it works a bit better like that).
Edit 3: There is no need to know the number of nested brackets as you can do something like:
$oldtext = "";
$newtext = $text;
while ($newtext != $oldtext)
{
$oldtext = $newtext;
$newtext = preg_replace(regexp,replace,$oldtext);
}
$text = $newtext;
Basically, this keeps running the regular expression replace until the output is the same as the input.
Note that I don't know PHP, so there are probably syntax errors in the above.
This is impossible to do in one regular expression since you want to keep content in multiple "hierarchies" of the content. It would be possible otherwise, using a recursive regular expression.
Anyways, here's the simplest, most greedy regular expression I can think of. It should only replace if the content matches your exact requirements.
You will need to escape all backslashes when putting it into a string (\ becomes \\.)
\[\[((?:[^][|]+|(?!\[\[|]])[^|])++\|?)*]]
As others have already explained, you use this with multiple passes. Keep looping while there are matches, performing replacement (only keeping match group 1.)
Difference from other regular expressions here is that it will allow you to have single brackets in the content, without breaking:
test1:[[link]] test2:[[gold|si[lv]er]]
test3:[[out1[[in[si]de]]out2]] test4:this|not
becomes
test1:[[link]] test2:si[lv]er
test3:out1in[si]deout2 test4:this|not
Why try to do it all in one go. Remove the [[]] first and then deal with options, do it in two lines of code.
When trying to get something going favour clarity and simplicity.
Seems like you have all the pieces.
Why not just simply remove any brackets that are left?
$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not';
$str = preg_replace('/\\[\\[(?:[^|\\]]+\\|)+([^\\]]+)\\]\\]/', '$1', $str);
$str = str_replace(array('[', ']'), '', $str);
Well, I didn't stick to just regex, because I'm of a mind that trying to do stuff like this with one big regex leads you to the old joke about "Now you have two problems". However, give something like this a shot:
$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not'; $reg = '/(.*?):(.*?)( |$)/';
preg_match_all($reg, $str, $m);
foreach($m[2] as $pos => $match) {
if (strpos($match, '|') !== FALSE && strpos($match, '[[') !== FALSE ) {
$opt = explode('|', $match); $match = $opt[count($opt)-1];
}
$m[2][$pos] = str_replace(array('[', ']'),'', $match );
}
foreach($m[1] as $k=>$v) $result[$k] = $v.':'.$m[2][$k];
This is C# using only using non-escaped strings, hence you will have to double the backslashes in other languages.
String input = "test1:[[link]] " +
"test2:[[gold|silver]] " +
"test3:[[out1[[inside]]out2]] " +
"test4:this|not";
String step1 = Regex.Replace(input, #"\[\[([^|]+)\|([^\]]+)\]\]", #"[[$2]]");
String step2 = Regex.Replace(step1, #"\[\[|\]\]", String.Empty);
// Prints "test1:silver test3:out1insideout2 test4:this|not"
Console.WriteLine(step2);
$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not';
$s = preg_split("/\s+/",$str);
foreach ($s as $k=>$v){
$v = preg_replace("/\[\[|\]\]/","",$v);
$j = explode(":",$v);
$j[1]=preg_replace("/.*\|/","",$j[1]);
print implode(":",$j)."\n";
}

Categories