Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 正则表达式,不包括包装在特定bbcode标记中的匹配项_Javascript_Php_Regex_Bbcode - Fatal编程技术网

Javascript 正则表达式,不包括包装在特定bbcode标记中的匹配项

Javascript 正则表达式,不包括包装在特定bbcode标记中的匹配项,javascript,php,regex,bbcode,Javascript,Php,Regex,Bbcode,我试图用卷曲引号替换双引号,除非文本被包装在某些标记中,如[quote]和[code] 样本输入 [quote="Name"][b]Alice[/b] said, "Hello world!"[/quote] <p>"Why no goodbye?" replied [b]Bob[/b]. "It's always Hello!"</p> [quote="Name"][b]Alice[/b] said, "Hello world!"[/quote] <p>“

我试图用卷曲引号替换双引号,除非文本被包装在某些标记中,如[quote]和[code]

样本输入

[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
<p>"Why no goodbye?" replied [b]Bob[/b]. "It's always Hello!"</p>
[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
<p>“Why no goodbye?” replied [b]Bob[/b]. “It's always Hello!”</p>
Javascript正则表达式分解

  • 内部
    split()
    • (\[(?icode | quote | code)[^\]*?\](?:)*?\[\/(\k)\])
      -捕获括号内的模式:
      • \[(?quote | code | icode)[^\]*?\]
        -a
        [quote]
        [code]
        [icode]
        打开标记,带或不带
        =html
        等参数,例如
        [code=html]
      • (?:[\s]*?)*?
        -任何字符(
        )的任何0+(尽可能少)次出现,前面是否有空格,因此如果开头标记后面有换行符,它不会中断
      • [\s]*?
        -0+空格
      • \[\/(\k)\]
        -
        [\quote]
        [\code]
        ,或
        [\icode]
        结束标记。匹配
        (?)
        组中捕获的文本。如果它是一个报价开始标签,它将是一个报价结束标签
  • 内部
    replace()
    • (?![^ |[^\[]*\])“([^”]*?)”
      -捕获双引号内的文本:
      • (?![^ |[^\[]*]
        -负向前看,查找字符(不是
        ]
        并丢弃它们,因此它不会匹配bbcode和html标记中的任何内容。例如:
        [spoiler=“Name”]
        。请注意,包装在标记中的匹配项保持不变
      • -文字开头双引号字符
      • ([^“]*?)
        -任何0+字符,双引号除外
      • -文字结尾双引号字符
  • SPLIT()正则表达式演示:

    这太糟糕了,因为替换被执行了多次


    同时,使用单个PHP正则表达式也可以获得相同的结果

    (\[(?quote | code | icode)[^\]*?\](?:[\s]*?)*?[\s]*?\[\/(\k)\](*跳过)(*F)|(?![^\[*])([^”]*?)
    
    PHP正则表达式分解

    • (\[(?quote | code | icode)[^\]*?\](?:[\s]*?*?[\s]*?\[\/(\k)\])(*SKIP)(*F)
      -匹配捕获括号内的模式,就像上面的javascript
      split()
      ,然后
      (*SKIP)(*F)
      使正则表达式引擎忽略匹配的文本
    • |
      -或
    • (?![^\[]*\])“([^”]*?)”
      -以与javascript
      replace()
      相同的方式捕获双引号内的文本
    PHP演示:


    这个正则表达式的美妙之处在于它只需要运行一次。不需要拆分和连接字符串。有没有办法在javascript中实现它?

    嵌套标记很难用rx解析,特别是JS的正则表达式。复杂的正则表达式也很难读取、维护和调试。如果您的需要很简单,可以使用排除一些禁用的标签,考虑基于ReXEPS的简单代码替代方案:

    function curly(str) {
        var excludes = {
            quote: 1,
            code: 1,
            icode: 1
        },
        xpath = [];
    
        return str.split(/(\[[^\]]+\])/) // breakup by tag markup
            .map(x => { // for each tag and content:
                if (x[0] === "[") { // tag markup:
                    if (x[1] === "/") { // close tag
                        xpath.pop(); // remove from current path
                    } else { // open tag
                        xpath.push(x.slice(1).split(/\W/)[0]); // add to current path
                    } //end if open/close tag
                } else { // tag content
                    if (xpath.every(tag =>!excludes[tag])) x = x.replace(/"/g, function repr() {
                        return (repr.z = !repr.z) ? "“" : "”"; // flip flop return value (naive)
                    });
                } //end if markup or content?
                return x;
            }) // end term map
            .join("");
    } /* end curly() */
    
    var input = `[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
    <p>"Why no goodbye?" replied [b]Bob[/b]. "It's always Hello!"</p>`;
    
    var wants = `[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
    <p>“Why no goodbye?” replied [b]Bob[/b]. “It's always Hello!”</p>`;
    
    curly(input) == wants; // true
    
    函数卷曲(str){
    var不包括={
    报价:1,
    代码:1,,
    国际编码:1
    },
    xpath=[];
    返回str.split(/(\[^\]]+\]/)//按标记标记拆分
    .map(x=>{//对于每个标记和内容:
    如果(x[0]==“[”){//标记标记:
    如果(x[1]==“/”{//“)关闭标记
    xpath.pop();//从当前路径中删除
    }else{//open标记
    xpath.push(x.slice(1.split(//\W/)[0]);//添加到当前路径
    }//如果打开/关闭标记,则结束
    }else{//标记内容
    if(xpath.every(tag=>!excludes[tag])x=x.replace(/“/g,函数repr(){
    返回(repr.z=!repr.z)?“”:“”;//触发器返回值(朴素)
    });
    }//如果是标记或内容,则结束?
    返回x;
    })//结束术语映射
    .加入(“”);
    }/*末端卷曲()*/
    var input=`[quote=“Name”][b]Alice[/b]说,“你好,世界!”[/quote]
    “为什么不说再见呢?”鲍勃回答说,“总是你好!”;
    var wants=`[quote=“Name”][b]Alice[/b]说,“你好,世界!”[/quote]
    “为什么不说再见呢?”鲍勃回答说,“总是你好!”;
    卷曲(输入)=需要;//真
    
    在我看来,尽管代码稍微长一点,但它允许文档、缩进和显式命名,这使得这些半复杂的逻辑操作更容易理解


    如果您的需求更复杂,请使用真正的BBCode JavaScript解析器,并根据需要映射/过滤/缩减其模型。

    因为JS缺少回溯动词,您需要使用这些括号中的块,但稍后会按原样替换它们。通过从您自己的正则表达式中获得替代的第二个方面,最终的正则表达式将是:

    \[(quote|i?code)[^\]]*\][\s\S]*?\[\/\1\]|(?![^<]*>|[^\[]*\])"([^"]*)"
    
    如果第一个捕获组存在,则上面的三元运算符返回
    $0
    (整个匹配),否则它将第二个捕获组值括在卷曲引号中并返回它

    注意:在不同的情况下,这可能会失败


    参见

    实际上我认为这和它所得到的一样好;用正则表达式解析DOM是很难的。如果你想要一个更干净的解决方案,我会考虑解析DOM而不是使用正则表达式。在给定的输入字符串中没有卷曲的引号。请考虑从给定的输入字符串提供预期的输出。@ ReVo不应该。在输入中使用卷曲引号,因为它们要添加到输出中。它们并不重要,正则表达式的要点是用{something}替换{thing}我在问题中添加了一个简短的输入/输出示例,但鉴于正则表达式可能会以多种方式失败,为了更彻底,在演示中有一个较长的示例输入。由于此任务包括处理html,因此它不会
    function curly(str) {
        var excludes = {
            quote: 1,
            code: 1,
            icode: 1
        },
        xpath = [];
    
        return str.split(/(\[[^\]]+\])/) // breakup by tag markup
            .map(x => { // for each tag and content:
                if (x[0] === "[") { // tag markup:
                    if (x[1] === "/") { // close tag
                        xpath.pop(); // remove from current path
                    } else { // open tag
                        xpath.push(x.slice(1).split(/\W/)[0]); // add to current path
                    } //end if open/close tag
                } else { // tag content
                    if (xpath.every(tag =>!excludes[tag])) x = x.replace(/"/g, function repr() {
                        return (repr.z = !repr.z) ? "“" : "”"; // flip flop return value (naive)
                    });
                } //end if markup or content?
                return x;
            }) // end term map
            .join("");
    } /* end curly() */
    
    var input = `[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
    <p>"Why no goodbye?" replied [b]Bob[/b]. "It's always Hello!"</p>`;
    
    var wants = `[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
    <p>“Why no goodbye?” replied [b]Bob[/b]. “It's always Hello!”</p>`;
    
    curly(input) == wants; // true
    
    \[(quote|i?code)[^\]]*\][\s\S]*?\[\/\1\]|(?![^<]*>|[^\[]*\])"([^"]*)"
    
    str.replace(regex, function($0, $1, $2) {
        return $1 ? $0 : '“'  + $2 + '”';
    })