【问题标题】:How to parse formatted text that resembles an .ini file?如何解析类似于 .ini 文件的格式化文本?
【发布时间】:2021-04-04 21:19:55
【问题描述】:

我有一个 HTML 输入表单,用于使用 PHP 将用户数据导入数据库 (MYSQL)。

输入中的信息必须是这样的:

[account]
user = {user1}
pwd = {password1}
expdate = 2028-01-01
[account]
user = {user2}
pwd = {password2}
expdate = 2028-01-01
[account]
user = {user3}
pwd = {password3}
expdate = 2028-01-01

现在,PHP 代码应该解析用户数和每个用户信息,并分别保存每个用户信息。

我的 PHP 代码是:

$users = $_POST["users"];
$users = explode(chr(10) . chr(10), $users);
for ($i = 0; $i < count($users); $i++) { 
    $users[$i] = explode(" ", $users[$i]);
    $username = $users[$i][2];
    $pwd = $users[$i][5];
    $exp = $users[$i][8];
    if (strtotime($exp) === false) {
        // ...code
    } else {
        $expiredate = date("Y-m-d", strtotime($exp));
    }
}

当输入是单个用户时:

[account]
user = {user1}
pwd = {password1}
expdate = 2028-01-01

我的输出被破坏了(这里是var_export() 输出):

array (
  'username' => '{user1}
pwd',
  'pwd' => '=',
  'exp' => '2028-01-01'
)

问题在于爆炸——pwd 键附加到 username 值、pwd=,它有时会给出错误的日期格式,从而无法保存。

作为一种解决方法,在每个输入的用户名和密码后面加上空格后,所有数据都解析成功。

另外,当我在输入表单中输入多个用户时:

[account]
user = {user1} 
pwd = {password1} 
expdate = 2028-01-01
[account]
user = {user2}
pwd = {password2}
expdate = 2028-01-01

PHP 代码只读取第一个用户并只保存第一个用户的信息,我希望它们都被保存。

所以:

  • 我希望 PHP 代码解析所有要保存的用户信息,而不仅仅是第一个用户。
  • 我希望保存用户信息,而不是在用户和密码行的末尾添加空格。

试图编辑我的代码并搜索了很多,很不幸,不知道PHP代码有什么问题。

【问题讨论】:

  • 看起来像一个 .ini 文件?如果是这样,请参阅:stackoverflow.com/questions/5695145/…
  • 感谢您的评论兄弟..它不是一个ini文件..它只是正常的配置文件数据。类似于 ini ..
  • $users[$i]=explode(" ",$users[$i]);你按空格分割输入我不认为这是正确的!例如:用户名“John Doe”将是 $users[i][0] John 和 $users[i][1] Doe,我建议发送 html 代码,这是我认为的主要问题
  • 您的输入看起来像一个.ini 文件。使用explode() 将输入字符串拆分为多个片段,然后使用函数parse_ini_string() 解析每个片段并获取数组中的数据。

标签: php explode text-parsing


【解决方案1】:

你可以这样试试

PHP - HTML :
<div class="all_forms">
<?php for ($z = 0; $z < 5; $z++) { ?>
<form method="POST" id="passenger-<?= $z ?>-details">
   <input type="text" class="form-control" name="username" placeholder="Username">
   <input type="password" class="form-control" name="password" placeholder="Password">
   <input type="date" class="form-control" name="date" placeholder="date">
</form>
<?php } ?>
</div>
JavaScript - JQuery
var passenger_details_array = [];
   $('.all_forms').find("form").map(function(idx, form) {
      var str = $('#' + form.id).serialize();
      passenger_details_array.push(str);
   });
   var data = {
      token: 'SOME_SECURITY_TOKEN',
      passenger_details: passenger_details_array
   };
   $.post('http://domain/path/file.php', data, function(response) {
            console.log(response);
   });
PHP - Saving Info

$passenger_details = $_POST['passenger_details'];
foreach ($passenger_details as $value) {
   parse_str($value, $tmp);
//here you have $tmp and in this you will find all proper details like (one by one)
// ['username' => 'U1', 'password' => 'user1_pass', 'date' => 'whatever']
}

//$passenger_details has data like

[
      ['username' => 'U1', 'password' => 'user1_pass', 'date' => 'whatever'],
      ['username' => 'U2', 'password' => 'user2_pass', 'date' => 'whatever'],
      ['username' => 'U3', 'password' => 'user3_pass', 'date' => 'whatever']
]

【讨论】:

    【解决方案2】:

    您的输入看起来像一个.ini 文件。
    使用explode() 将输入字符串拆分为由[account] 分隔的片段,然后使用parse_ini_string() 解析每个片段并获取数组中的数据:

    $users = <<< END
    [account]
    user = {user1}
    pwd = {password1}
    expdate = 2028-01-01
    [account]
    user = {user2}
    pwd = {password2}
    expdate = 2028-01-01
    [account]
    user = {user3}
    pwd = {password3}
    expdate = 2028-01-01
    END;
    
    // Use $users = $_POST['users'] in the real code
    
    // Parse the input data
    $data = array_map(
        function($entry) { return parse_ini_string($entry); },
        array_filter(           // remove the empty entries (before the first '[account]', between two consecutive appearances of '[account]'
            explode('[account]', $users),
            function($entry) { return strlen(trim($entry)); }
        )
    );
    
    print_r($data);
    

    输出是:

    Array
    (
        [1] => Array
            (
                [user] => {user1}
                [pwd] => {password1}
                [expdate] => 2028-01-01
            )
    
        [2] => Array
            (
                [user] => {user2}
                [pwd] => {password2}
                [expdate] => 2028-01-01
            )
    
        [3] => Array
            (
                [user] => {user3}
                [pwd] => {password3}
                [expdate] => 2028-01-01
            )
    
    )
    

    Check it online.

    接下来,处理解析的信息就很简单了:

    foreach ($data as $account) {
      // do something with $account['user'], $account['pwd'], $account['expdate']
      // Use the DateTime class and its friends to validate and handle $account['expdate']
    }
    

    parse_ini_string() 能够在一次调用中解析整个字符串并在其第二个参数为true 时正确处理这些部分。但是,因为所有部分都命名为account,所以它会合并值;输入中稍后出现的键值对会覆盖之前的值。
    这就是为什么我们首先将输入分成多个部分,然后一次一个部分地馈送到parse_ini_string()

    【讨论】:

    • 仅供参考,我刚刚对问题进行了大量编辑,以删除大量不必要/不相关的问题/代码膨胀。这会使您的全面代码审查的某些部分无效。尽管您的回答异常慷慨,但事实是,问题应该在得到任何答案之前很久就被摆弄了。赏金不允许忽略呈现minimal reproducible example 的期望。我相信我的编辑已经把这个问题变成了未来研究人员会费心去阅读的东西。
    • @mickmackusa 我完全同意。这个问题现在更容易阅读,可以更好地帮助读者。我从我的答案中删除了对从问题中删除的代码的分析。答案现在也更容易阅读了:-)
    【解决方案3】:

    使用可选的前导换行符序列和强制的尾随换行符序列分割[account] 行。不允许在爆炸中产生空元素。

    \R 匹配与平台无关的换行符序列,因此不必担心 \r\n\n 的问题。

    ^(字符串锚点的开头)被 m 模式修饰符修改,使其与每一行的开头匹配。

    ? 表示零或之前的任何内容之一。这使得结尾的 \R 成为可选的。

    如果您的真实文本在用户详细信息之间有一个空行,您可以在前导 \R 之后添加 {2} 以消耗额外的换行符序列。

    在每个生成的元素上调用parse_ini_string()。清洁并完成;不需要额外的过滤或修整。爆炸过程不再有麻烦。

    代码:(Demo)

    $data = <<<NOT_INI
    [account]
    user = {user1}
    pwd = {password1}
    expdate = 2028-01-01
    [account]
    user = {user2}
    pwd = {password2}
    expdate = 2028-01-01
    [account]
    user = {user3}
    pwd = {password3}
    expdate = 2028-01-01
    NOT_INI;
    
    var_export(
        array_map(
            'parse_ini_string',
            preg_split(
                '~\R?^\[account]\R~m',
                $data,
                0,
                PREG_SPLIT_NO_EMPTY
            )
        )
    );
    

    输出:

    array (
      0 => 
      array (
        'user' => '{user1}',
        'pwd' => '{password1}',
        'expdate' => '2028-01-01',
      ),
      1 => 
      array (
        'user' => '{user2}',
        'pwd' => '{password2}',
        'expdate' => '2028-01-01',
      ),
      2 => 
      array (
        'user' => '{user3}',
        'pwd' => '{password3}',
        'expdate' => '2028-01-01',
      ),
    )
    

    【讨论】:

    • @BHappy 我希望你能回到 Stack Overflow 并亲自将赏金奖励给最佳答案,而不是让时间用完,系统会根据投票结果自动提名收件人。跨度>
    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 2018-06-24
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 2019-03-09
    • 1970-01-01
    • 2011-12-17
    相关资源
    最近更新 更多