PHP RegEx被解析2次

时间:2017-05-11 01:59:37

标签: php regex

我正在开发一个PHP脚本,它接受纯文本文件任务列表并解析如下内容:

  • 项目名称标题,因为它以分号结尾:==项目
  • 任务以- task name
  • 开头
  • @ tag-name包含<span class="tag">@tag-name</span>
  • @done包裹着<span class="tag done">@done</span>
  • 以及其他

下面的PHP函数是替换的内容......

function get_marked_up_todo($todo){
    $todo = htmlspecialchars($todo,ENT_QUOTES)."\n\n";
    $search = array('/(.+:)(.+)\n\n/sU',     // Get projects
                    '/(- ([^\@\n]+).+)/',    // Get todos
                    '/(.+:)/',               // Get headings
                    '/\n([^\<\n].+)/',       // Get notes
                    '/- (.+@done)/',         // Get done
                    '/(@due\([^\)]+\))/',    // Get due tags
                    '/(@(?!due)[^\s]+)/',    // Get tags
                    "/\t/",
                    '/`(.*?)`/',             // inline code
                    );
    $replace = array("<div class=\"project\">\n$1$2\n</div>\n\n",
                    '<span class="todo"><input type="checkbox" value="'.trim('\2').'"> \1</span>',
                    '<h1>\1</h1>',
                    "\n\t<span class=\"note\">$1</span>",
                    '<span class="bullet-done">? ? ??</span> - <strike>\1</strike>',
                    '<span class="tag due">\1</span>',
                    '<span class="tag">\1</span>',
                    "\t<span class=\"tab\"></span>",
                    '<code>\1</code>',
                    );
    return preg_replace($search, $replace, $todo);
}

在上面的搜索和替换数组中,两个数组中的最后一项是我添加的新模式,用于查找包含在Markdown内联代码等反引号中的内联代码。

问题是,在输出中,每个任务项行都会在任务行的前面添加一个复选框输入字段,并在此复选框的值中解析我的代码。

只有当我添加像此内联代码或我添加的任何其他项目(如粗体文本和斜体的RegEx)时,所有其他替换RegEx才会显示在复选框值中。

为什么我的复选框值显示在HTML中,而其他人都没有?

我已经设置了一个演示来显示PHP的输出 -  https://3v4l.org/f0e8W#output

以下是完整的代码

<?php
echo "<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>TODO.todo</title></head>
<body>
<style>
.project {
    line-height: 4px;
}
.bullet-done {
    font-weight: bold;
    font-style: normal;
    color: rgba(0,114,62,1.0);
}
.note{
display: block;
color: rgba(133,130,102,1.0);
font-weight: normal;
font-style: normal;
}
.todo {
    display: inline-block;
}
.tag {
    font-weight: bold;
    font-style: normal;
    color: rgba(160,46,43,0.6);
}
body {
    background: rgba(239,233,183,1.0);
    color: rgba(0,0,0,0.31);
    font-weight: normal;
    font-style: normal;
}
h1 {
    font-weight: bold;
    font-style: normal;
    background: rgba(0,0,0,0.06);
    color: rgba(188,100,74,1.0);
    width: 100%;
    line-height: 34px;
}
.tab{
    display: inline-block;
    width:0px;
    height: 0px;
    background: #000000;
</style><pre>";
$todo = 'Version 1:
This file is in TaskPaper format.
Tabs are used to indent.
    Each task begins with a "- ".
Projects end with a ":".
Tags are in the format "@tag_name".
All other lines (such as these) are considered as notes,
and are to be ignored.

- User signup
- Register for an account
    - Log in @done
    - Forget password

- Manage users
    - Create users @in_progress
    - Delete users
    - User profile page @40%

- Blog
    - Creating new posts @done
    - Comments @done
    - Moderating comments @done

This is my todo list:
    This is a note about the list.
    - this is an item  @done
    - and this is @me 
this is a note about my done item
  - this is the last @java @shopping @item @done

This is a second list:
- Add more funk to something @work @java 
    - Send something somewhere @work @email @due(12 Aug 07)
        - this is an example
- dfgdfg
ggg
hfghf  
- hgh
- dfygdfgdf

List:
- gdfgdf `inline code` hhf
- gdfgdf
- dfgdfg @done
        ';

echo get_marked_up_todo($todo);

echo '</pre></body></html>';

function get_marked_up_todo($todo){
    $todo = htmlspecialchars($todo,ENT_QUOTES)."\n\n";
    $search = array('/(.+:)(.+)\n\n/sU',     // Get projects
                    '/(- ([^\@\n]+).+)/',    // Get todos
                    '/(.+:)/',               // Get headings
                    '/\n([^\<\n].+)/',       // Get notes
                    '/- (.+@done)/',         // Get done
                    '/(@due\([^\)]+\))/',    // Get due tags
                    '/(@(?!due)[^\s]+)/',    // Get tags
                    "/\t/",
                    '/`(.*?)`/',             // inline code
                    );
    $replace = array("<div class=\"project\">\n$1$2\n</div>\n\n",
                    '<span class="todo"><input type="checkbox" value="'.trim('\2').'"> \1</span>',
                    '<h1>\1</h1>',
                    "\n\t<span class=\"note\">$1</span>",
                    '<span class="bullet-done">? ? ??</span> - <strike>\1</strike>',
                    '<span class="tag due">\1</span>',
                    '<span class="tag">\1</span>',
                    "\t<span class=\"tab\"></span>",
                    '<code>\1</code>',
                    );
    return preg_replace($search, $replace, $todo);
}

1 个答案:

答案 0 :(得分:1)

如果我正确理解了该问题,那么您的问题是当您使用自己的替代<code>时,<input>标记如下所示:

<input type="checkbox" value="gdfgdf <code>inline code</code> hh">

但您希望它不包含<code>...</code>部分,如下所示:

<input type="checkbox" value="gdfgdf ">

如果我的理解是正确的,那么你修复了你只需要修复负责呈现<input>标记的RegExp,就是这个:

'/(- ([^\@\n]+).+)/', // Get todos

它的工作方式是从-开始,直到@或换行符(\n)出现。你想添加反引号:

'/( - ([^ \ @ \ n] +)。+)/',//获取待办事项

这将使RegExp在遇到第一个时停止捕获`并将解决您的问题(再次,如果我理解正确的话)。