我只需要做一个快速匹配并替换来自 xml 的所有内容。 我不想表达该文件,因为该文件就像 100mb,我无法阻止这种情况。 所以这是示例数据。
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product active="1" on_sale="0" discountable="0">
<sku>SKUTARGET</sku>
<name><![CDATA[sdfsdf (NET)]]></name>
<description><![CDATA[agag adgsgsdg asdgsdg]]></description>
<keywords></keywords>
<price>9.000000</price>
<stock_quantity>35</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>PVC</material>
<barcode>883045010070</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/sdssd/sdfsd.jpg</image>
<image>/AL10sdfsds07XO/sdfsd.jpg</image>
</images>
<categories>
<category code="166" video="0" parent="172">sd & Sexy sdf</category>
<category code="172" video="0" parent="">sd & dddsdsds</category>
<category code="641" video="0" parent="172">sdfsdf Costume sdfsdfsdf</category>
</categories>
<manufacturer code="AL" video="0">sdfsdf sdfs</manufacturer>
<type code="LI" video="0">sdfsd</type>
</product>
<product active="1" on_sale="0" discountable="0">
<sku>XXXXXXX</sku>
<name><![CDATA[LEATHER sdfsdf (NET)]]></name>
<description><![CDATA[asdgsdgsd sad sadg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg]]></description>
<keywords></keywords>
<price>5.000000</price>
<stock_quantity>36</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>Leather</material>
<barcode>883045300164</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/AL10sds0XO/sdsdsd.jpg</image>
<image>/sdsds/AL1sd00XOB.jpg</image>
<image>/AL1sdsds00XO/sdsds.jpg</image>
</images>
<categories>
<category code="80" video="0" parent="44">sdgsdgsdg</category>
<category code="181" video="0" parent="172">Sleep & Lounge</category>
</categories>
<manufacturer code="AL" video="0">Allure sdsds</manufacturer>
<type code="LI" video="0">sdsfsdfsd</type>
</product>
</products>
我需要的只是从节点产品开始的一个块,在这种情况下,sku 是一个变量"SKUTARGET">
<product active="1" on_sale="0" discountable="0">
<sku>SKUTARGET</sku>
<name><![CDATA[sdfsdf (NET)]]></name>
<description><![CDATA[agag adgsgsdg asdgsdg]]></description>
<keywords></keywords>
<price>9.000000</price>
<stock_quantity>35</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>PVC</material>
<barcode>883045010070</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/sdssd/sdfsd.jpg</image>
<image>/AL10sdfsds07XO/sdfsd.jpg</image>
</images>
<categories>
<category code="166" video="0" parent="172">sd & Sexy sdf</category>
<category code="172" video="0" parent="">sd & dddsdsds</category>
<category code="641" video="0" parent="172">sdfsdf Costume sdfsdfsdf</category>
</categories>
<manufacturer code="AL" video="0">sdfsdf sdfs</manufacturer>
<type code="LI" video="0">sdfsd</type>
</product>
这是我目前正在使用的代码
<?php
ob_start();
?>
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product active="1" on_sale="0" discountable="0">
<sku>SKUTARGET</sku>
<name><![CDATA[sdfsdf (NET)]]></name>
<description><![CDATA[agag adgsgsdg asdgsdg]]></description>
<keywords></keywords>
<price>9.000000</price>
<stock_quantity>35</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>PVC</material>
<barcode>883045010070</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/sdssd/sdfsd.jpg</image>
<image>/AL10sdfsds07XO/sdfsd.jpg</image>
</images>
<categories>
<category code="166" video="0" parent="172">sd & Sexy sdf</category>
<category code="172" video="0" parent="">sd & dddsdsds</category>
<category code="641" video="0" parent="172">sdfsdf Costume sdfsdfsdf</category>
</categories>
<manufacturer code="AL" video="0">sdfsdf sdfs</manufacturer>
<type code="LI" video="0">sdfsd</type>
</product>
<product active="1" on_sale="0" discountable="0">
<sku>XXXXXXX</sku>
<name><![CDATA[LEATHER sdfsdf (NET)]]></name>
<description><![CDATA[asdgsdgsd sad sadg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg]]></description>
<keywords></keywords>
<price>5.000000</price>
<stock_quantity>36</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>Leather</material>
<barcode>883045300164</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/AL10sds0XO/sdsdsd.jpg</image>
<image>/sdsds/AL1sd00XOB.jpg</image>
<image>/AL1sdsds00XO/sdsds.jpg</image>
</images>
<categories>
<category code="80" video="0" parent="44">sdgsdgsdg</category>
<category code="181" video="0" parent="172">Sleep & Lounge</category>
</categories>
<manufacturer code="AL" video="0">Allure sdsds</manufacturer>
<type code="LI" video="0">sdsfsdfsd</type>
</product>
</products>
<?php
$xml_str = ob_get_contents();
ob_end_clean();
$tar_sku="SKUTARGET"; // this is the sku of the product block I need to have
$pat= '/^.*(<product *<sku>'.$tar_sku.'</sku>*</product>).*$/is'; // this should match the block with the sku but no other block
$replacement='$1';//This should overwrite everything with that found block.
$returnValue = preg_replace($pat, $replacement, $xml_str);
任何帮助都会很棒。 谢谢。杰里米
[编辑]
这是下面建议中的测试代码。 到目前为止,仍然不起作用。 我期望通过该 SKU 匹配回显 xml 块的字符串。 还没有运气。
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
umask(0);
$xml_str = <<<EOD
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product active="1" on_sale="0" discountable="0">
<sku>SKUTARGET</sku>
<name><![CDATA[sdfsdf (NET)]]></name>
<description><![CDATA[agag adgsgsdg asdgsdg]]></description>
<keywords></keywords>
<price>9.000000</price>
<stock_quantity>35</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>PVC</material>
<barcode>883045010070</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/sdssd/sdfsd.jpg</image>
<image>/AL10sdfsds07XO/sdfsd.jpg</image>
</images>
<categories>
<category code="166" video="0" parent="172">sd & Sexy sdf</category>
<category code="172" video="0" parent="">sd & dddsdsds</category>
<category code="641" video="0" parent="172">sdfsdf Costume sdfsdfsdf</category>
</categories>
<manufacturer code="AL" video="0">sdfsdf sdfs</manufacturer>
<type code="LI" video="0">sdfsd</type>
</product>
<product active="1" on_sale="0" discountable="0">
<sku>XXXXXXX</sku>
<name><![CDATA[LEATHER sdfsdf (NET)]]></name>
<description><![CDATA[asdgsdgsd sad sadg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg]]></description>
<keywords></keywords>
<price>5.000000</price>
<stock_quantity>36</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>Leather</material>
<barcode>883045300164</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/AL10sds0XO/sdsdsd.jpg</image>
<image>/sdsds/AL1sd00XOB.jpg</image>
<image>/AL1sdsds00XO/sdsds.jpg</image>
</images>
<categories>
<category code="80" video="0" parent="44">sdgsdgsdg</category>
<category code="181" video="0" parent="172">Sleep & Lounge</category>
</categories>
<manufacturer code="AL" video="0">Allure sdsds</manufacturer>
<type code="LI" video="0">sdsfsdfsd</type>
</product>
</products>
EOD;
$tar_sku="SKUTARGET"; // this is the sku of the product block I need to have
$pattern = "~<product .*?<sku>$tar_sku</sku>.*?</product>~is";
$returnValue = preg_match($pattern,$xml_str);
echo '--'.$returnValue[0];
不要使用正则表达式来解析 XML。如果您担心内存使用量,则使用正则表达式将比增量解析消耗更多的内存。由于正则表达式只能对字符串进行操作,因此您至少需要 100MB 的内存来保存文件字符串,然后才能对其进行任何操作。如果使用增量 XML 分析器,则可以使用的内存少于文件大小。
这项工作的正确工具是 XMLReader
.
博士
此答案中有两种XMLReader
解析实现:
-
getmatchingproducts_xml_expand()
或getmatchingproducts_xml_noexpand()
函数返回所有匹配产品的列表。内存使用情况取决于源 xml 中匹配的 SKU 产品数量。 -
ProductMatcher
类是一个迭代器(可以在foreach
中使用(,它将以字符串、DOMDocument
或SimpleXMLElement
的形式增量返回匹配的产品。无论您的源 XML 有多大或有多少产品匹配,它都会使用大约 1MB 的内存。
测试文件
我使用您创建的格式创建了一个 120 MB 的示例文件。这是创建代码:
function maketestfile() {
$xml = <<<EOT
<product active="1" on_sale="0" discountable="0">
<sku>{{SKU}}</sku>
<name><![CDATA[LEATHER sdfsdf (NET)]]></name>
<description><![CDATA[asdgsdgsd sad sadg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg asdg]]></description>
<keywords></keywords>
<price>5.000000</price>
<stock_quantity>36</stock_quantity>
<reorder_quantity>0</reorder_quantity>
<height>0.000000</height>
<length>0.000000</length>
<diameter>0.000000</diameter>
<weight>0.000000</weight>
<color>Black</color>
<material>Leather</material>
<barcode>883045300164</barcode>
<release_date>2008-11-10</release_date>
<images>
<image>/AL10sds0XO/sdsdsd.jpg</image>
<image>/sdsds/AL1sd00XOB.jpg</image>
<image>/AL1sdsds00XO/sdsds.jpg</image>
</images>
<categories>
<category code="80" video="0" parent="44">sdgsdgsdg</category>
<category code="181" video="0" parent="172">Sleep & Lounge</category>
</categories>
<manufacturer code="AL" video="0">Allure sdsds</manufacturer>
<type code="LI" video="0">sdsfsdfsd</type>
</product>
EOT;
$fo = fopen('test2.xml', 'wb');
fwrite($fo, "<?xml version='"1.0'" encoding='"UTF-8'"?>'n");
fwrite($fo, "<products>'n");
$sku = array('SKUTARGET', 'XXXXXXXX', 'SKUY12345', '124432XXK', 'FOO1234BAR');
for ($i=0; $i < 100000; $i++) {
shuffle($sku);
fwrite($fo, str_replace('{{SKU}}', $sku[0], $xml));
}
fwrite($fo, "</products>'n");
fclose($fo);
}
记忆和定时功能
function trial($method, $args) {
//prime the pump
if (!function_exists($method))
throw BadFunctionCallException();
call_user_func_array($method, $args);
$iter = 2;
$runtime = 0;
for ($i=0; $i < $iter; $i++) {
$start = microtime(true);
$res = call_user_func_array($method, $args);
$runtime += microtime(true)-$start;
}
return array(
'peakmem' => memory_get_peak_usage(),
'mem' => memory_get_usage(),
'time' => $runtime/$iter,
'return' => $res,
);
}
function main($method, $filename) {
$args = array($filename, 'SKUTARGET');
$res = trial($method, $args);
echo "Found products: ",count($res['return']),"'n";
printf("%30s %3.2f %3.2f %4.3f'n", $method, $res['peakmem']/(1024*1024), $res['mem']/(1024*1024), $res['time']);
}
main($argv[1], $argv[2]);
Regex vs XMLReader
最后,我测试了这些功能。前两个使用其他答案建议的正则表达式,第三个使用XMLReader
。
function getmatchingproducts_regex1($xmlfile, $desiredsku) {
$pattern = "~<product [^<]*<sku>".preg_quote($desiredsku,'~')."</sku>.*?</product>~Sus";
$xmlstr = file_get_contents($xmlfile);
preg_match_all($pattern, $xmlstr, $matchingproducts);
return $matchingproducts;
}
function getmatchingproducts_regex2($xmlfile, $desiredsku) {
$pattern = "~<product [^<]*+<sku>".preg_quote($desiredsku,'~')."</sku>[^<]*(?:<(?!/product>)[^<]*)*</product>~Su";
$xmlstr = file_get_contents($xmlfile);
preg_match_all($pattern, $xmlstr, $matchingproducts);
return $matchingproducts;
}
function getmatchingproducts_xml_expand($xmlfile, $desiredsku) {
$r = new XMLReader();
$r->open($xmlfile, null, LIBXML_COMPACT);
$matchingproducts = array();
do {
// advance to first product element
$r->read();
} while ($r->nodeType!==XMLReader::NONE
and !($r->nodeType===XMLReader::ELEMENT and $r->name==='product' and !$r->isEmptyElement));
while ($r->nodeType!==XMLReader::NONE) {
if ($r->nodeType===XMLReader::ELEMENT and $r->name==='product' and !$r->isEmptyElement) {
$dom = $r->expand(new DOMDocument('1.0','UTF-8'));
$sxe = simplexml_import_dom($dom);
if ((string) $sxe->sku===$desiredsku) {
// Matching product found.
// We have access to the <product> element and contents as:
// * raw text via $r->readOuterXml()
// * DOMDocument via $dom
// * SimpleXML via $sxe
// Pick the one you want and save:
$matchingproducts[] = $r->readOuterXml();
// null the rest to be very conservative about memory
$dom = $sxe = null;
}
}
// optimization--skip to next product sibling
$r->next('product');
}
$r->close();
return $matchingproducts;
}
最后,我将所有这些保存在一个文件中,并在我的双核8GB系统上运行它。(数字是峰值内存、最终内存和每次迭代的秒数。"找到的产品"只是为了验证匹配的产品数量是否正确。
$ php xmlreader.php getmatchingproducts_xml_expand test2.xml
Found products: 19969
getmatchingproducts_xml_expand 86.96 58.17 10.648
$ php xmlreader.php getmatchingproducts_regex1 test2.xml
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1253 bytes) in xmlreader.php on line 72
$ php xmlreader.php getmatchingproducts_regex2 test2.xml
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1253 bytes) in xmlreader.php on line 78
您会注意到,正则表达式方法甚至无法在不耗尽可用内存的情况下运行!此外,XMLReader
方法(除了实际正确解析 XML 之外(使用的内存少于文件大小。我愿意打赌,大部分getmatchingproducts_xml_expand
内存也是$matchedproducts
数组,而不是解析。 通过将解析器函数包装在一个类中,可以进一步减少内存使用量,以便一次检索一个匹配项。
不过,使用正则表达式的优点是它要快得多。这是另一个尝试,将内存限制提高到 1GB:
$ php -d memory_limit=1G xmlreader.php getmatchingproducts_regex1 test2.xml
Found products: 19968
getmatchingproducts_regex1 181.31 30.01 1.421
$ php -d memory_limit=1G xmlreader.php getmatchingproducts_regex2 test2.xml
Found products: 19968
getmatchingproducts_regex2 181.31 30.01 0.906
所有这些速度都来自忽略XML解析规则并将其视为字符串。(有趣的是,整个文件都在内存中这一事实并不影响XMLReader
的速度,只影响它的内存使用量。
如果您需要快速访问和低内存使用率,则需要某种索引或数据库。您可以使用 sqlite、sqlite3、dbm 创建一个平面文件数据库,并使用 XMLReader
加载由 SKU 键入的产品。然后,不要读取 XML 文件,而是从数据库中加载该产品的 xml 字符串。
只是为了踢,我尝试了一种不使用扩展的XMLReader
解析方法,看看是否可以节省时间或内存。不过,差异可以忽略不计,代码也不太清楚。
function getmatchingproducts_xml_noexpand($xmlfile, $desiredsku) {
$r = new XMLReader();
$r->open($xmlfile, null, LIBXML_COMPACT);
$matchingproducts = array();
$candidateproduct = null;
do {
// advance to first product element
$r->read();
} while ($r->nodeType!==XMLReader::NONE
and !($r->nodeType===XMLReader::ELEMENT and $r->name==='product' and !$r->isEmptyElement));
while ($r->nodeType!==XMLReader::NONE) {
if ($r->nodeType===XMLReader::ELEMENT and $r->name==='product' and !$r->isEmptyElement) {
$candidateproduct = array($r->readOuterXML(), $r->depth);
$r->read();
while ($r->depth > $candidateproduct[1]) {
if ($r->nodeType===XMLReader::ELEMENT and $r->name==='sku' and $r->readString()===$desiredsku) {
$matchingproducts[] = $candidateproduct[0];
$r->next('product');
break;
} else {
$r->next();
}
}
$candidateproduct = null;
} else {
$r->next();
}
}
$r->close();
return $matchingproducts;
}
$ php xmlreader.php getmatchingproducts_xml_noexpand test2.xml
Found products: 19969
getmatchingproducts_xml_noexpand 86.95 58.17 13.716
以增量方式返回解析结果
又一次实现。这可能与这所能达到的效率一样高。它使用不到 1MB 的内存解析 120MB 的测试文件。
class ProductMatcher implements Iterator {
// return values for next()
const R_STR = 'product_str'; // return string
const R_DOM = 'product_dom'; // return DOMDocument
const R_SXE = 'product_sxe'; // return SimpleXMLElement
protected $reader;
protected $productcount = null;
protected $product_str = null;
protected $product_dom = null;
protected $product_sxe = null;
protected $xmlfile;
protected $returnmethod;
public $desiredsku;
function __construct($xmlfile, $desiredsku, $returnmethod=self::R_STR) {
$this->xmlfile = $xmlfile;
$this->desiredsku = $desiredsku;
$this->setReturnMethod($returnmethod);
}
function __destruct() {
if (isset($this->reader)) {
$this->reader->close();
}
}
protected function _create() {
$this->productcount = null;
$this->reader = new XMLReader();
$this->reader->open($this->xmlfile, null, LIBXML_COMPACT);
}
protected function _start() {
$r =& $this->reader;
do {
// advance to first product element
$r->read();
} while ($r->nodeType!==XMLReader::NONE
and !($r->nodeType===XMLReader::ELEMENT and $r->name==='product' and !$r->isEmptyElement));
}
protected function advance() {
$r =& $this->reader;
$productfound = false;
$this->product_str = $this->product_sxe = $this->product_dom = null;
while ($r->nodeType!==XMLReader::NONE and !$productfound) {
if ($r->nodeType===XMLReader::ELEMENT and $r->name==='product' and !$r->isEmptyElement) {
// xmlreader_print($r);
$dom = $r->expand(new DOMDocument('1.0','UTF-8'));
$sxe = simplexml_import_dom($dom);
if ((string) $sxe->sku===$this->desiredsku) {
$this->product_str = $r->readOuterXml();
$this->product_sxe = $sxe;
$this->product_dom = $dom;
$productfound = true;
$this->productcount = (isset($this->productcount)) ? $this->productcount+1 : 0;
}
}
// optimization--skip to next product sibling
$r->next('product');
}
if (!$productfound) {
$this->productcount = null;
}
}
public function setReturnMethod($method) {
$this->returnmethod = $method;
}
public function getReturnMethod() {
return $this->returnmethod;
}
public function rewind() {
$this->_create();
$this->_start();
$this->advance();
}
public function valid() {
return $this->productcount!==null;
}
public function current() {
return $this->{$this->returnmethod};
}
public function key() {
return $this->productcount;
}
public function next() {
$this->advance();
}
}
function timeProductMatcher($filename) {
$matcher = new ProductMatcher($filename, 'SKUTARGET');
foreach ($matcher as $m) {}
$runtime = 0;
$iter = 2;
for ($i=0; $i < $iter; $i++) {
$start = microtime(true);
$matcher = new ProductMatcher($filename, 'SKUTARGET');
foreach ($matcher as $n => $match) {}
$runtime += microtime(true)-$start;
}
echo "Found products: ",$n+1, "'n";
printf("%30s %3.2f %3.2f %4.3f'n", 'ProductMatcher', memory_get_peak_usage()/(1024*1024), memory_get_usage()/(1024*1024), $runtime/$iter);
}
timeProductMatcher($argv[1]);
结果:
$ php xmlreader.php test2.xml
Found products: 19969
ProductMatcher 0.76 0.75 10.394
扩展示例用法:
$matcher = new ProductMatcher($filename, 'SKUTARGET', ProductMatcher::R_SXE);
foreach ($matcher as $product) {
// $product is a SimpleXMLElement because we specified R_SXE
(string) $product->sku === 'SKUTARGET'; // true
}
如果只想提取匹配的<product>..</product>
位,请使用 preg_match
,而不是preg_replace
。
$pattern = "~<product .*?<sku>$tar_sku</sku>.*?</product>~is";
$returnValues = preg_match($pat,$xml_str);
这里$returnValues
是一个数组,它要么是空的,要么有一个包含您所追求的相关 XML 位的 elment $returnValues[0]
。
这是因为preg_match
在第一场比赛时停止。如果您知道整个 XML 中只有一个对应的SKUTARGET
,请使用 preg_match
。如果您认为可能有多个,并且想要提取所有内容,请使用 preg_match_all
。
正则表达式与您的基本相同,除了:
- 如果正则表达式中有内部
/
,则不能使用/
来分隔正则表达式(如/regex/
(,除非您转义它们。所以你必须在</sku>
等中逃离/
。我已将分隔符更改为~
,因此我无需费心转义我的内部/
. -
<product *
-><product .*
(前者仅匹配空格( -
</sku>*</product>
-></sku>.*?</product>
(前者仅匹配 0 或更多>
/sku
之后。 - 例如,将贪婪
.*
更改为非贪婪.*?
,以防止抓取属于下一个产品的 XML。
不要使用正则表达式来解析 xml。相反,请使用适用于 php 的 xml 工具系列。目前还不清楚你想在这里做什么。看起来您想从文档中挑选出一个特定的元素并将其替换为其他元素。下面是一个示例。
[编辑] 好的,所以如果你想处理大的xml文件,使用xmlreader。
代码的主要问题是你错误地使用了preg_match
。 返回值只是一个整数,表示正则表达式匹配的次数,即 0
或 1
。 如果要检索匹配的文本,则必须提供一个数组来存储它:
preg_match($pattern, $subject, $matches);
但是正则表达式也存在一个问题,如果您将第二个<product>
元素作为目标而不是第一个元素,您将看到它。 比赛仍然从第一个<product>
元素开始,然后继续到第二个元素的结束。 不情愿的.*?
不足以保证尽可能短的比赛,因为它只影响比赛结束的地方,而不是比赛开始的地方。
您需要确保在它匹配开始<product>
标记后,在找到<sku>
标记之前,它不能再匹配任何<product>
或</product>
标记。 假设<sku>
始终是<product>
元素中列出的第一个元素,那么将第一个.*?
更改为[^<]*
很简单:
"~<product [^<]*<sku>$tar_sku</sku>.*?</product>~is"
此外,考虑到文件的大小,使正则表达式尽可能高效可能是值得的。 为此,我会将第一个量词设为所有格 - [^<]*+
- 并将其他.*?
量词替换为更具确定性的东西。
"~<product [^<]*+<sku>$tar_sku</sku>[^<]*(?:<(?!/product>)[^<]*)*</product>~"
请注意,我还删除了修饰符;s
标志现在无关紧要,因为正则表达式中没有点,并且 i
标志可能从不需要,因为 XML 标记名称区分大小写。 如果 SKU 不是,您可以使用内联修饰符将 i
标志仅应用于正则表达式的该部分,即 (?i:...)
:
"~<product [^<]*+<sku>(?i:$tar_sku)</sku>[^<]*(?:<(?!/product>)[^<]*)*</product>~"
下面是一个演示:http://ideone.com/mZqFz