Here is a problem.
i am exploding a list of character by new line in an array. and doing array unique on it. but it is not working as expected.
below is code:
$list = "test
ok
test
test
ok
ok
test";
$list_explode = explode("\n", $list); //exploding the characters of the list from the input
//displaying unique
array_map('trim', $list_explode);
$result = array_unique($list_explode);
print_r($result);
The result is
Array ( [0] => test [1] => ok [6] => test )
use var_dump instead of print_r and you'll see there difference between the "test"s (take a look at codepad).
your code contains \r\n as linebreaks and you're splittoing at \n, so \r is still there at all entrys except the last one.
you're already using array_map to prevent this but forgot to use the retun-value (it doesn't work by reference) in the latter code. change that line to:
$list_explode = array_map('trim', $list_explode);
after doing this, you'll get what you expect (see at codepad again).
You've failed to take into account that your string has a sequence of \r\n for the line break. In exploding you've only removed the \n portion so what your result actually looks like is:
Array ( [0] => test\r [1] => ok [6] => test )
However, the \r does not print as a visible character (even though the code sees it).
You can split multiple lines of text in two main ways:
Use $list_explode = array_map('rtrim', explode("\n", $list));
Use $list_explode = preg_split("/\r?\n/", $list);
Related
I am using Virtualmin and testing out the Remote API PHP features for a project. I can't seem to find any good documentation on this so I am testing out different functions randomly.
Making an API call is done like this:
<?php
$result = shell_exec("wget -O - --quiet --http-user=root --http-passwd=pass --no-check-certificate 'https://localhost:10000/virtual-server/remote.cgi?program=list-users&domain=testdomain.co.uk'");
echo $result;
?>
The issue I am facing is the result output is plain text formatted in a way which is easily readable. I have provided an example image below. I have tried using explode to create an array which is easily manageable but I cannot explode by blank space as parts such as "real name" or the actual real names have spaces? This also seems to output tens of empty array parts [1] => [2] => [3] => [4] => [5] =>
This is what I currently have which is providing numerous empty array values.
$lines = explode("\n", $result);
$out = array();
foreach ($lines as $line) {
$parts = explode(" ", $line);
}
Ideally I would like the array to work like a multidimensional array.
I need help to find out the strings from a text which starts with # and till the next immediate space by preg_match in php
Ex : I want to get #string from this line as separate.
In this example, I need to extract "#string" alone from this line.
Could any body help me to find out the solutions for this.
Thanks in advance!
PHP and Python are not the same in regard to searches. If you've already used a function like strip_tags on your capture, then something like this might work better than the Python example provided in one of the other answers since we can also use look-around assertions.
<?php
$string = <<<EOT
I want to get #string from this line as separate.
In this example, I need to extract "#string" alone from this line.
#maybe the username is at the front.
Or it could be at the end #whynot, right!
dog#cat.com would be an e-mail address and should not match.
EOT;
echo $string."<br>";
preg_match_all('~(?<=[\s])#[^\s.,!?]+~',$string,$matches);
print_r($matches);
?>
Output results
Array
(
[0] => Array
(
[0] => #string
[1] => #maybe
[2] => #whynot
)
)
Update
If you're pulling straight from the HTML stream itself, looking at the Twitter HTML it's formatted like this however:
<s>#</s><b>UserName</b>
So to match a username from the html stream you would match with the following:
<?php
$string = <<<EOT
<s>#</s><b>Nancy</b> what are you on about?
I want to get <s>#</s><b>string</b> from this line as separate. In this example, I need to extract "#string" alone from this line.
<s>#</s><b>maybe</b> the username is at the front.
Or it could be at the end <s>#</s><b>WhyNot</b>, right!
dog#cat.com would be an e-mail address and should not match.
EOT;
$matchpattern = '~(<s>(#)</s><b\>([^<]+)</b>)~';
preg_match_all($matchpattern,$string,$matches);
$users = array();
foreach ($matches[0] as $username){
$cleanUsername = strip_tags($username);
$users[]=$cleanUsername;
}
print_r($users);
Output
Array
(
[0] => #Nancy
[1] => #string
[2] => #maybe
[3] => #WhyNot
)
Just do simply:
preg_match('/#\S+/', $string, $matches);
The result is in $matches[0]
I have a huge string from a server, and I want each line as an object (for later foreach loop).
This is part of the string:
1535;;34290;;teaserbanner_881.jpg;;Not allowed;;closed;;;;closed;;
1535;;34291;;teaserbanner_8832.jpg;;Not allowed;;closed;;;;closed;;
1379;;31912;;teaserbanner_844.jpg;;Allowed;;open;;;;open;;
1379;;31913;;teaserbanner_8422.jpg;;allowed;;closed;;;;closed;;
The only thing that stays the same for each line is the "closing tags"
only two options:
;;closed;;;;closed;;
;;open;;;;open;;
I was thinking that it should be the needle for explode or some regex...
The final output should be:
element[0] 1535;;34290;;teaserbanner_881.jpg;;Not allowed;;closed;;;;closed;;
element[1] 1535;;34291;;teaserbanner_8832.jpg;;Not allowed;;closed;;;;closed;;
element[2] 1379;;31912;;teaserbanner_844.jpg;;Allowed;;open;;;;open;;
element[3] 1379;;31913;;teaserbanner_8422.jpg;;allowed;;closed;;;;closed;;
The string doesn't come in "lines" it is one big line.
You can make use of preg_match_all function:
$s = <<< EOF
1535;;34290;;teaserbanner_881.jpg;;Not allowed;;closed;;;;closed;;
1535;;34291;;teaserbanner_8832.jpg;;Not allowed;;closed;;;;closed;;
1379;;31912;;teaserbanner_844.jpg;;Allowed;;open;;;;open;;
1379;;31913;;teaserbanner_8422.jpg;;allowed;;closed;;;;closed;;
EOF;
if (preg_match_all('~(.*?;;(open|closed);{4}\2;;)~', $s, $arr))
print_r($arr[1]);
OUTPUT:
Array
(
[0] => 1535;;34290;;teaserbanner_881.jpg;;Not allowed;;closed;;;;closed;;
[1] => 1535;;34291;;teaserbanner_8832.jpg;;Not allowed;;closed;;;;closed;;
[2] => 1379;;31912;;teaserbanner_844.jpg;;Allowed;;open;;;;open;;
[3] => 1379;;31913;;teaserbanner_8422.jpg;;allowed;;closed;;;;closed;;
)
Please have a look at split. split("\n", $string) will give you an array, where each entry is one line of the string.
You can use file() for this:-
$lines = file('path/to/file');
foreach($lines as $line){
//do something with $line
}
$lines is an array with each element representing a line in the file so that
var_dump($lines);
Would give something like:-
array (size=4)
0 => string '1535;;34290;;teaserbanner_881.jpg;;Not allowed;;closed;;;;closed;;' (length=68)
1 => string '1535;;34291;;teaserbanner_8832.jpg;;Not allowed;;closed;;;;closed;; ' (length=69)
2 => string '1379;;31912;;teaserbanner_844.jpg;;Allowed;;open;;;;open;; ' (length=60)
3 => string '1379;;31913;;teaserbanner_8422.jpg;;allowed;;closed;;;;closed;;' length=63)
Try using preg_split:
$array = preg_split('/(?<=;;closed;;;;closed;;|;;open;;;;open;;)(?!$)/', $string)
(?<=;;closed;;;;closed;;|;;open;;;;open;;) makes sure there are the closing tags before the point of splitting and (?!$) makes sure the string isn't split at the end.
viper7 demo
What does huge mean?
exploding() something actually huge will deplete your PHP memory.
You need to parse it old school, char by char and add them to a bucket. When your condition is met (like the 5th ; or 10th ; or whatever...), consider the bucket a proper object and handle it. But don't store it. Push it to a file, a DB or something.
If things are not that huge, use a regular expression with an 'object' format. Like:
// keep duplicating the (.*?);; until you reach your number of columns.
preg_match_all '~(.*?);;(.*?);;(.*?);;(.*?);;(.*?);;~s' // pseudo-code :)
And this will break it all into objects and properties. Which you can iterate and use.
I have bunch of strings like this:
a#aax1aay222b#bbx4bby555bbz6c#mmm1d#ara1e#abc
And what I need to do is to split them up based on the hashtag position to something like this:
Array
(
[0] => A
[1] => AAX1AAY222
[2] => B
[3] => BBX4BBY555BBZ6
[4] => C
[5] => MMM1
[6] => D
[7] => ARA1
[8] => E
[9] => ABC
)
So, as you see the character right behind the hashtag is captured plus everything after the hashtag just right before the next char+hashtag.
I've the following RegEx which works fine only when I have a numeric value in the end of each part.
Here is the RegEx set up:
preg_split('/([A-Z])+#/', $text, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
And it works fine with something like this:
C#mmm1D#ara1
But, if I change it to this (removing the numbers):
C#mmmD#ara
Then it will be the result, which is not good:
Array
(
[0] => C
[1] => D
)
I've looked at this question and this one also, which are similar but none of them worked for me.
So, my question is why does it work only if it has followed by a number? and how I can solve it?
Here you can see some of them sample strings which I have:
a#123b#abcc#def456 // A:123, B:ABC, C:DEF456
a#abc1def2efg3b#abcdefc#8 // A:ABC1DEF2EFG3, B:ABCDEF, C:8
a#abcdef123b#5c#xyz789 // A:ABCDEF123, B:5, C:XYZ789
P.S. Strings are case-insensitive.
P.P.S. If you ever thinking what the hell are these strings, they are user submitted answers to a questionnaire, and I can't do anything on them like refactoring as they are already stored and just need to be proceed.
Why Not Using explode?
If you look at my examples you will see that I need to capture the character right before the # as well. If you think it's possible with explode() please post the output as well, thanks!
Update
Should we focus on why /([A-Z])+#/ works only if numbers included? thanks.
Instead of using preg_split(), decide what you want to match instead:
A set of "words" if followed by either <any-char># or <end-of-string>.
A character if immediately followed by #.
$str = 'a#aax1aay222b#bbx4bby555bbz6c#mmm1d#ara1e#abc';
preg_match_all('/\w+(?=.#|$)|\w(?=#)/', $str, $matches);
Demo
This expression uses two look-ahead assertions. The results are in $matches[0].
Update
Another way of looking at it would be this:
preg_match_all('/(\w)#(\w+)(?=\w#|$)/', $str, $matches);
print_r(array_combine($matches[1], $matches[2]));
Each entry starts with a single character, followed by a hash, followed by X characters until either the end of the string is encountered or the start of a next entry.
The output is this:
Array
(
[a] => aax1aay222
[b] => bbx4bby555bbz6
[c] => mmm1
[d] => ara1
[e] => abc
)
If you still want to use preg_split you can remove the + and it might work as expected:
'/([A-Z])#/i'
Since then you only match the hashtag and ONE alpha character before, and not all them.
Example: http://codepad.viper-7.com/z1kFDb
Edit: Added a case-insensitive flag i in the pattern.
Use explode() rather than Regexp
$tmpArray = explode("#","a#aax1aay222b#bbx4bby555bbz6c#mmm1d#ara1e#abc");
$myArray = array();
for($i = 0; $i < count($tmpArray) - 1; $i++) {
if (substr($tmpArray[$i],0,-1)) $myArray[] = substr($tmpArray[$i],0,-1);
if (substr($tmpArray[$i],-1)) $myArray[] = substr($tmpArray[$i],-1);
}
if (count($tmpArray) && $tmpArray[count($tmpArray) - 1]) $myArray[] = $tmpArray[count($tmpArray) - 1];
edit: I updated my answer to reflect better reading the questions
You can use explode() function that will split the string except the hash signs, like stated in the answers given before.
$myArray = explode("#",$string);
For the string 'a#aax1aay222b#bbx4bby555bbz6c#mmm1d#ara1e#abc' this returns something like
$myarray = array('a', 'aax1aay22b', 'bbx4bby555bbz6c' ....);
All you need now is to take the last character of each string in array as another item.
$copy = array();
foreach($myArray as $item){
$beginning = substr($item,0,strlen($item)-1); // this takes all characters except the last one
$ending = substr($item,-1); // this takes the last one
$copy[] = $beginning;
$copy[] = $ending;
} // end foreach
This is an example, not tested.
EDIT
Instead of substr($item,0,strlen($item)-1); you might use substr($item,0,-1);.
I am getting data from an API and the resulting string is
[RESPONSE]
PROPERTY[STATUS][0]=ACTIVE
PROPERTY[REGISTRATIONEXPIRATIONDATE][0]=2012-04-04 19:48:48
DESCRIPTION=Command completed successfully
QUEUETIME=0
CODE=200
RUNTIME=0.352
QUEUETIME=0
RUNTIME=0.8
EOF
I am trying to convert this into an array like
Array(
['PROPERTY[STATUS][0]'] => ACTIVE,
['CODE'] => 200,
...
);
So I am trying to explode it using the resulting file_get_content function with an explode like
$output = explode('=',file_get_contents($url));
But the problem is the returning values are not always returned in the same order, so I need to have it like $array['CODE'] = 200, and $array['RUNTIME'] = 0.352 however there does not seem to be any kind of new line characters? I tried \r\n, \n, <br>, \r\n\r\n in the explode function to no avail. But there is new lines in both notepad and the browser.
So my question is there some way to determine if a string is on a new line or determine what the character forcing the new line is? If not is there some other way I could read this into an array?
To find out what the breaking character is, you could do this (if $data contatins the string example you've posted):
echo ord($data[strlen('[RESPONSE]')]) . PHP_EOL;
echo ord($data[strlen('[RESPONSE]')+1]); // if there's a second char
Then take a look in the ASCII table to see what it is.
EDIT: Then you could explode the data using that newly found character:
explode(ord($ascii_value), $data);
Btw, does file() return a correct array?
Explode on "\n" with double quotes so PHP understands this is a line feed and not a backslashed n ;-) then explode each item on =
Why not just use parse_ini_file() or parse_ini_string()?
It should do everything you need (build an array) in one easy step.
Try
preg_split("/$/m", $str)
or
preg_split("/$\n?/m", $str)
for the split
The lazy solution would be:
$response = strtr($response, "\r", "\n");
preg_match_all('#^(.+)=(.+)\s*$#m', $response, $parts);
$parts = array_combine($parts[1], $parts[2]);
Gives you:
Array (
[PROPERTY[STATUS][0]] => ACTIVE
[PROPERTY[REGISTRATIONEXPIRATIONDATE][0]] => 2012-04-04 19:48:48
[DESCRIPTION] => Command completed successfully
[QUEUETIME] => 0
[CODE] => 200
[RUNTIME] => 0.8