正则如何完整匹配script标签的中间内容?

PHP文件如下:

<script src="static/js/jsencrypt.js?v=<?= WEB_VERSION ?>"></script>
<script src="static/js/jquery.form.js?v=<?= WEB_VERSION ?>"></script>
<script type="text/javascript">
    var a = 1;
    var b = 2;
</script>

如何通过正则表达式捕获到script标签中间部分的内容,例如 第三个script标签内容为:

    var a = 1;
    var b = 2;

我自己写了的一段正则:/(<script\b[^>]*>)([\s\S]*?)(<\/script>)/gm
这段正则只能匹配script标签属性不插入>的情况,如果script标签属性插入了>就会匹配错误。

阅读 4.3k
avatarAI BotBETA

正则表达式是用来匹配字符串的,而你的问题中,script标签的属性中包含了>,这使得正则表达式无法正确匹配。

你的正则表达式 /<script\b[^>]*>([\s\S]*?)<\/script>/gm 的问题在于它假设script标签的属性中不会包含>,而实际上,你的示例中script标签的属性中就包含了>

一个更好的解决方案是使用DOM解析器来解析HTML,然后提取出script标签的内容。这样可以更准确地处理各种情况,包括属性中包含>的情况。

如果你坚持要使用正则表达式,那么你可能需要一个更复杂的正则表达式,可以处理HTML中的各种情况。这样的正则表达式通常被称为“贪婪”的,并且可能会非常复杂和难以维护。

如果你只是想提取出script标签的内容,我建议你使用DOM解析器。在PHP中,你可以使用DOMDocument类来做到这一点。以下是一个示例:

$dom = new DOMDocument();
@$dom->loadHTML($html); // $html 是你的HTML字符串
$scripts = $dom->getElementsByTagName('script');

foreach ($scripts as $script) {
    echo $script->nodeValue . "\n";
}

这段代码将遍历所有的script标签,并打印出它们的内容。注意,这只会提取出script标签的文本内容,而不会提取出内嵌的JavaScript代码。如果你需要提取出内嵌的JavaScript代码,你可能需要使用一个更复杂的解析器或工具,例如PHP的tidy扩展或外部的HTML解析库。

4 个回答

属性中含有引号就排除引号干扰

/(<script\b([^"<>]+|"[^"]*")*>)([\s\S]*?)(<\/script>)/g

如果是 Javascript 的话,建议使用 DOMParser 解析 html 字符串:

const htmlStr = `<script src="static/js/jsencrypt.js?v=<?= WEB_VERSION ?>"></script>
<script src="static/js/jquery.form.js?v=<?= WEB_VERSION ?>"></script>
<script type="text/javascript">
    var a = 1;
    var b = 2;
</script>`;

const parser = new DOMParser();

console.log(
  parser.parseFromString(htmlStr, "text/html")
        .querySelectorAll("script")[2]
    ?.innerHTML
);
    var a = 1;
    var b = 2;
/**
 * 获取html代码中指定标签名的内容
 * @param htmlStr html字符串
 * @param tagName 标签名称
 * @param isGetTagInnerContent 是否只获取标签内部的内容
 */
function getCodeByTagName (htmlStr, tagName, isGetTagInnerConten) {
  let reg = new RegExp(`<${tagName}[^>]*>([\\s\\S]*)<\\/${tagName}>`);
  if (isGetTagInnerContent) {
    reg = new RegExp(`(?<=<${tagName}[^>]*>)([\\s\\S]*)(?=<\/${tagName}>)`);
  }
  // console.log('reg', reg);
  let matched = htmlStr.match(reg);
  return matched ? matched[0] : '';
};


let str = `<script type="text/javascript">
    var a = 1;
    var b = 2;
</script>`;
// 输出:\n    var a = 1;\n    var b = 2;\n
console.log(getCodeByTagName(str, 'script', true));

image.png

一般来说script标签有内容的会标签会有type="text/javascript"那么可以:
(?<=<script.*type="text\/javascript".*>)([\s\S]*?)(?=\<\/script>)

js代码:

const regex = /(?<=<script.*type="text\/javascript".*>)([\s\S]*?)(?=\<\/script>)/gm;
const str = `
<script src="static/js/jsencrypt.js?v=<?= WEB_VERSION ?>"></script>
<script src="static/js/jquery.form.js?v=<?= WEB_VERSION ?>"></script>
<script type="text/javascript">
    var a = 1;
    var b = 2;
</script>
`;
let m;

while ((m = regex.exec(str)) !== null) {
    // 必须这样才能在零宽(位置)匹配时避免死循环
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // 可以通过变量`m`获取结果
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题