I have a large xml file (about 2mb) and need to replace all checkboxes and radio with my additional string => <i></i>
example
<input type="checkbox" />
replace with
<input type="checkbox" /><i></i>
the code is:
$file = 'style.xml';
$c = file_get_contents($file);
preg_match_all("#<input.*type=\"(checkbox|radio)\".+? />#i", $c, $m);
if($m)
{
for($i = 0; $i < count($m[0]); $i++)
{
/*$search = trim($m[0][$i]);
$replace = "$search<i></i>";*/
$c = preg_replace("#" . preg_quote($m[0][$i], "#") . "#i", $m[0][$i] . '<i></i>', $c);
}
}
if($fp = #fopen('new-style.xml', 'w'))
{
#flock($fp, 2);
#fputs($fp, $c);
#flock($fp, 3);
#fclose($fp);
}
it works, but sometimes replaced with more than one "I" tag
example
<input type="checkbox" /><i></i><i></i><i></i><i></i>
<input type="radio" /><i></i><i></i><i></i>
my regex is wrong? or something else?
how to make replacement only once for string?
screenshot here
image
There's no need to iterate over matches. You can just do it all with a single preg_replace.
preg_replace("#<input.*type=\"(?:checkbox|radio)\".*? />#i", "$0<i></i>", $c);
It matches any checkbox or radio input tag, and replaces that match with $0<i></i> where the $0 refers to the entire match.
Related
I'm learning PHP and started a small project with some file handling involved, a database checker on numbers (to keep it simple). What I mean by that is when you type in a number and hit the submit button php is going to search through a text file to get a name by the number.
The text file looks like:
1 Sandra
2 Piet
3 Francis
etc...
The code:
<?php
// Type your code here
$val = $row = NULL;
if (isset($_POST["submit"])) {
$myFile = fopen("testData.txt","r");
$number = $_POST["input"];
$cntNumber = strlen($number);
while (!feof($myFile)){
$val = fgetc($myFile);
if (is_numeric($val)) {
if ($cntNumber > 1) {
// Point where I Don't know what to do
} elseif ($val == $number) {
$row = fgets($myFile);
}
}
}
}
?>
<div style="width: 232px; height: 100px; border: 1px solid gray; margin-bottom: 5px;">
<?php
echo $row . "<br>";
?>
</div>
<form action="index.php" method="post">
<input name="input" placeholder="Number" type="text">
<input name="submit" value="Search" type="submit">
</form>
So if the number has more than one digit it has to search for the next matching digit, but I don't know how I can achieve that. I hope my explanation was clear enough, if not don't mind asking some question's.
Thanks in advance
I don't know whether you want to use f-file functions, but simplier solution is:
if (isset($_POST["submit"])) {
$myFile = file("testData.txt");
// print_r $myFile and see that this is array of lines
$number = $_POST["input"];
// iterate over your lines:
foreach ($myFile as $line) {
// as each line contains two values divided by a space,
// you can explode the line into two parts
$parts = explode(' ', $line);
// print_r($parts) to see result
// next check first part which is number:
if ($parts[0] == $number) {
echo 'Found!';
break; // exit loop as your value is found
}
}
}
If you want to use f-file functions then code can be:
$fh = fopen("testData.txt", "r");
while(!feof($fh)) {
$str = fgets($fh, 1024);
$parts = explode(' ', $str);
// print_r($parts) to see result
if ($parts[0] == $number) {
echo 'Found!' . $str;
break; // exit loop as your value is found
}
}
But I strongly recommend you to use databases as storages.
I have assignment to find the length of string without white space and without using any string function anyone help me please
You can use regular expressions and the function preg_match_all:
$value = "This is a test string.";
$length = preg_match_all ('/[^ ]/' , $value, $matches);
echo $length; //18
Here you can find a working example: https://3v4l.org/IPlJi
explanation:
Between [^ and ] you have to add all characters which should not be count to the length of the string. For example: if you want to filter out the character i and (space) you have to set the following pattern: [^ i].
Code to filter i and (space):
$value = "This is a test string.";
$length = preg_match_all('/[^ i]/' , $value, $matches);
echo $length; //15
be carefull with some characters:
If you want to exclude one of the following characters .^$*+?()[{\| you have to escape them with \. If you want to exclude the . too, you have the following code:
$value = "This is a test string.";
$length = preg_match_all ('/[^ \.]/' , $value, $matches);
echo $length; //18
how to test your pattern:
If you want to test your regular expressions for preg_match_all or other functions like that, you can use the following tool: http://www.phpliveregex.com/
This will work for you:
$string = "this is a nice string with spaces and chars";
$length = 0;
$i = 0;
while(isset($string[$i]))
{
if($string[$i] != ' ') $length++;
$i++;
}
var_dump($length);
var_dump(strlen($string));
Outputs:
int(35)
int(43)
<!doctype html>
<html>
<body>
<center>
<form action="#" method="get">
<br>
<input type="text" name="txt"/>
<br><br>
<input type="submit" name="submit"/>
<br><br>
</form>
<!---------------------------------------------------------------------->
<?php
if(isset($_GET["submit"])) {
$name = $_GET["txt"];
for ($i = 0; isset($name[$i]); $i++) {
$j = $i;
}
for ($k = $j; isset($name[$k]); $k--) {
echo $name[$k];
}
}
I am trying to scrape an ebay page such as this one: http://www.ebay.co.uk/sch/Cars-/9801/i.html?_nkw=vw+golf
Everything works great except one of my regular expressions just isn't matching the content and therefore the matches aren't being pushed to $linksArray I have outputted the contents to make sure what I am trying to match is infact there - and it is. I then go print_r($linksArray) where all the matches should be. but it's not. It is an empty multi dimensional array. You can see my live example here: http://www.mycommunity.co.za/marcksack/index.php
Here is my PHP code:
<?php
echo '<form method="POST">
<input type="text" id="url" name="url" size="120" value="' . (isset($_REQUEST["url"]) && !empty($_REQUEST["url"]) ? $_REQUEST["url"] : "") . '"/>
<input type="submit" value="Submit" />
</form>';
flush();
if (isset($_REQUEST["url"]) && !empty($_REQUEST["url"])) {
$url = $_REQUEST["url"];
$phones = array();
for ($page = 1; $page <= 1; $page++) {
// get page contents
$contents = file_get_contents($url . "&_pgn=" . $page);
echo(htmlentities($contents));
// find all links patterns
// HERE IS THE PROBLEM
$pattern = '/class="lvtitle"><a href="(.*)" class="vip"/';
$linksArray = array();
preg_match_all($pattern, $contents, $linksArray);
print_r($linksArray);
$links = $linksArray[0];
foreach($links as $link) {
$pureLink = str_replace("class=\"lvtitle\"><a href=\"", "", $link);
$pureLink = str_replace("\" class=\"vip\"", "", $pureLink);
// getting sub page contents
$subContents = file_get_contents($pureLink);
// find all links patterns
$subContents = str_replace(" ", "", $subContents);
$phonePattern = '/07[0-9]{9}/';
$phonesArray = array();
preg_match_all($phonePattern, $subContents, $phonesArray);
foreach($phonesArray[0] as $element) {
// check if phone not added previousely to the phones array
if (!in_array($element, $phones)) {
// add it to the phones array
array_push($phones, $element);
echo $element . "<br />";
flush();
}
}
}
}
// print results
foreach($phones as $phone){
echo $phone."<br/>";
}
}
?>
So obviously my question is what am I doing wrong? Why are the matches not being pushed to my $linksArray variable. I really appreciate your help!
This regex works:
"/ class=\"lvtitle\"><a href=\"([^\"]*)\" class=\"vip\"/"
A few issues with your's:
You were trying to capture the URL using (.*), which will match the entire line.
It was not matching the entire line because ebay has two spaces in between the class and href attributes.
Also, as has already been mentioned, you should use the API or DOMDocument for this. But in case you are curious, this is why it wasn't working. I hope that helps!
I've been working on this for a while and I can't seem to figure it out. I know it must be something really simple. Basically I have a script that works as a program that translates English to Piglatin, and it works fine, but I want the user to have a choice of whether or not to actually operate that script, by using a radio form with the text input that says "English" or "Piglatin". I've tried all different ways to get this to work, but using a nested conditional seems like it would be the most logical answer to me. However, whenever I try to run the script with it, it doesn't work. Can someone please tell me what I'm doing wrong?! It would be much appreciated. Thanks!
HTML Form:
<p><input type="text" name="original" size="20" maxlength="40" /></label></p>
<p><input type="radio" name="english" value="yes"/>english <input type="radio" name="english" value="no"/>piglatin</p>
<input type="submit" name="submit" value="submit" /></form>
PHP:
<?php # script
$original = $_REQUEST['original'];
$english = $_REQUEST['english'];
$array = explode(" ", $original);
if($english=="no")
{
piglatin = "";
foreach($array as $word)
{
$word = trim($word);
$first = substr($word,0,1);
$rest = substr($word,1,strlen($word)-1);
if (preg_match('/^[aeiou]/', $word)) {
$word = preg_replace('/^([aeiou].+)$/', "$1-way", $word);
}
elseif (preg_match('/^(th|sh)/', $word)) {
$word = preg_replace('/^(th|sh)(.+)$/', "$2-$1ay", $word);
}
else {
$word = preg_replace('/^[a-z](.+)$/', "$1-$first"."ay", $word);
}
$piglatin .= $word ." ";
echo $original ." becomes: ".$piglatin.".";
};
else
{echo $original.".";
};
?>
Like I said, I'm sure it's something really small and simple that I just can't see because I've been looking at the code so long. Any help is appreciated! Thank you!
Sort your indentation out and you will see your missing closing brackets.
<?php # script
$original = $_REQUEST['original'];
$english = $_REQUEST['english'];
$array = explode(" ", $original);
if($english=="no")
{
$piglatin = "";
foreach($array as $word)
{
$word = trim($word);
$first = substr($word,0,1);
$rest = substr($word,1,strlen($word)-1);
if (preg_match('/^[aeiou]/', $word)) {
$word = preg_replace('/^([aeiou].+)$/', "$1-way", $word);
} elseif (preg_match('/^(th|sh)/', $word)) {
$word = preg_replace('/^(th|sh)(.+)$/', "$2-$1ay", $word);
} else {
$word = preg_replace('/^[a-z](.+)$/', "$1-$first"."ay", $word);
}
$piglatin .= $word ." ";
echo $original ." becomes: ".$piglatin.".";
};
} else {
echo $original.".";
};
Basically I want to turn a string like this:
<code> <div> blabla </div> </code>
into this:
<code> <div> blabla </div> </code>
How can I do it?
The use case (bc some people were curious):
A page like this with a list of allowed HTML tags and examples. For example, <code> is a allowed tag, and this would be the sample:
<code><?php echo "Hello World!"; ?></code>
I wanted a reverse function because there are many such tags with samples that I store them all into a array which I iterate in one loop, instead of handling each one individually...
My version using regular expressions:
$string = '<code> <div> blabla </div> </code>';
$new_string = preg_replace(
'/(.*?)(<.*?>|$)/se',
'html_entity_decode("$1").htmlentities("$2")',
$string
);
It tries to match every tag and textnode and then apply htmlentities and html_entity_decode respectively.
There isn't an existing function, but have a look at this.
So far I've only tested it on your example, but this function should work on all htmlentities
function html_entity_invert($string) {
$matches = $store = array();
preg_match_all('/(&(#?\w){2,6};)/', $string, $matches, PREG_SET_ORDER);
foreach ($matches as $i => $match) {
$key = '__STORED_ENTITY_' . $i . '__';
$store[$key] = html_entity_decode($match[0]);
$string = str_replace($match[0], $key, $string);
}
return str_replace(array_keys($store), $store, htmlentities($string));
}
Update:
Thanks to #Mike for taking the time to test my function with other strings. I've updated my regex from /(\&(.+)\;)/ to /(\&([^\&\;]+)\;)/ which should take care of the issue he raised.
I've also added {2,6} to limit the length of each match to reduce the possibility of false positives.
Changed regex from /(\&([^\&\;]+){2,6}\;)/ to /(&([^&;]+){2,6};)/ to remove unnecessary excaping.
Whooa, brainwave! Changed the regex from /(&([^&;]+){2,6};)/ to /(&(#?\w){2,6};)/ to reduce probability of false positives even further!
Replacing alone will not be good enough for you. Whether it be regular expressions or simple string replacing, because if you replace the < > signs then the < and > signs or vice versa you will end up with one encoding/decoding (all < and > or all < and > signs).
So if you want to do this, you will have to parse out one set (I chose to replace with a place holder) do a replace then put them back in and do another replace.
$str = "<code> <div> blabla </div> </code>";
$search = array("<",">",);
//place holder for < and >
$replace = array("[","]");
//first replace to sub out < and > for [ and ] respectively
$str = str_replace($search, $replace, $str);
//second replace to get rid of original < and >
$search = array("<",">");
$replace = array("<",">",);
$str = str_replace($search, $replace, $str);
//third replace to turn [ and ] into < and >
$search = array("[","]");
$replace = array("<",">");
$str = str_replace($search, $replace, $str);
echo $str;
I think i have a small sollution, why not break html tags into an array and then compare and change if needed?
function invertHTML($str) {
$res = array();
for ($i=0, $j=0; $i < strlen($str); $i++) {
if ($str{$i} == "<") {
if (isset($res[$j]) && strlen($res[$j]) > 0){
$j++;
$res[$j] = '';
} else {
$res[$j] = '';
}
$pos = strpos($str, ">", $i);
$res[$j] .= substr($str, $i, $pos - $i+1);
$i += ($pos - $i);
$j++;
$res[$j] = '';
continue;
}
$res[$j] .= $str{$i};
}
$newString = '';
foreach($res as $html){
$change = html_entity_decode($html);
if($change != $html){
$newString .= $change;
} else {
$newString .= htmlentities($html);
}
}
return $newString;
}
Modified .... with no errors.
So, although other people on here have recommended regular expressions, which may be the absolute right way to go ... I wanted to post this, as it is sufficient for the question you asked.
Assuming that you are always using html'esque code:
$str = '<code> <div> blabla </div> </code>';
xml_parse_into_struct(xml_parser_create(), $str, $nodes);
$xmlArr = array();
foreach($nodes as $node) {
echo htmlentities('<' . $node['tag'] . '>') . html_entity_decode($node['value']) . htmlentities('</' . $node['tag'] . '>');
}
Gives me the following output:
<CODE> <div> blabla </div> </CODE>
Fairly certain that this wouldn't support going backwards again .. as other solutions posted, would, in the sense of:
$orig = '<code> <div> blabla </div> </code>';
$modified = '<CODE> <div> blabla </div> </CODE>';
$modifiedAgain = '<code> <div> blabla </div> </code>';
I'd recommend using a regular expression, e.g. preg_replace():
http://www.php.net/manual/en/function.preg-replace.php
http://www.webcheatsheet.com/php/regular_expressions.php
http://davebrooks.wordpress.com/2009/04/22/php-preg_replace-some-useful-regular-expressions/
Edit: It appears that I haven't fully answered your question. There is no built-in PHP function to do what you want, but you can do find and replace with regular expressions or even simple expressions: str_replace, preg_replace