【问题标题】:Problem dealing with a space when moving JSON to Python将 JSON 移动到 Python 时处理空格的问题
【发布时间】:2021-12-30 23:57:58
【问题描述】:

我是一名高中数学老师,正在自学编程。如果我没有正确表达其中的某些内容,我提前道歉。

我正在从用户那里收集 CSV 数据并尝试通过 Python 将其移动到 SQLite 数据库。

除非其中一个值有空格,否则一切正常。

例如,这是我的 JavaScript 对象的一部分:

Firstname: "Bruce"
Grade: ""
Lastname: "Wayne Jr"
Nickname: ""

这是申请JSON.stringify后对应的一块:

{"Firstname":"Bruce","Lastname":"Wayne Jr","Nickname":"","Grade":""}

然后通过表单将其传递给 Python。在 Python 中,我使用:

data = request.form.get("data")
print(data)
data2 = json.loads(data)
print(data2)

我收到一堆错误消息,以:json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 250 (char 249) 结尾,第一次打印的日志给出:

[{"Firstname":"Jason","Lastname":"Bourne","Nickname":"","Grade":"10"},
 {"Firstname":"Steve","Lastname":"McGarret","Nickname":"5-0","Grade":""},
 {"Firstname":"Danny","Lastname":"Williams","Nickname":"Dano","Grade":"12"},
 {"Firstname":"Bruce","Lastname":"Wayne

所以它似乎打破了"Wayne Jr" 的空间。

我用在这里学到的知识来构建基础知识:
https://bl.ocks.org/HarryStevens/0ce529b9b5e4ea17f8db25324423818f

我相信这个 JavaScript 函数正在解析用户数据:

function changeDataFromField(cb){
   var arr = [];
   $('#enter-data-field').val().replace( /\n/g, "^^^xyz" ).split( "^^^xyz" ).forEach(function(d){
     arr.push(d.replace( /\t/g, "^^^xyz" ).split( "^^^xyz" ))
   });
   cb(csvToJson(arr));
 }

基于 cmets 的更新:
我正在使用 POST 请求。没有 AJAX。

用户实际上有 2 个输入。他们可以在其中粘贴 CSV 数据和文件上传选项的文本框。这里还有一些 JavaScript。

// Use the HTML5 File API to read the CSV
  function changeDataFromUpload(evt, cb){
    if (!browserSupportFileUpload()) {
      console.error("The File APIs are not fully supported in this browser!");
    } else {
      var data = null;
      var file = evt.target.files[0];
      var fileName = file.name;
      $("#filename").html(fileName);

      if (file !== "") {
        var reader = new FileReader();

        reader.onload = function(event) {
          var csvData = event.target.result;
          var parsed = Papa.parse(csvData);
          cb(csvToJson(parsed.data));
        };
        reader.onerror = function() {
          console.error("Unable to read " + file.fileName);
        };
      }

      reader.readAsText(file);
      $("#update-data-from-file")[0].value = "";
    }
  }

  // Method that checks that the browser supports the HTML5 File API
  function browserSupportFileUpload() {
    var isCompatible = false;
    if (window.File && window.FileReader && window.FileList && window.Blob) {
      isCompatible = true;
    }
    return isCompatible;
  }

  // Parse the CSV input into JSON
  function csvToJson(data) {
    var cols = ["Firstname","Lastname","Nickname","Grade"];
    var out = [];
    for (var i = 0; i < data.length; i++){
      var obj = {};
      var row = data[i];
      cols.forEach(function(col, index){
        if (row[index]) {
          obj[col] = row[index];
        }
        else {
          obj[col] = "";
        }
      });
      out.push(obj);
    }
    return out;
  }

  //  Produces table for user to check appearance of data and button to complete upload
  function makeTable(data) {
    console.log(data);
    send_data = JSON.stringify(data);
    console.log(send_data);
      var table_data = '<table style="table-layout: fixed; width: 100%" class="table table-striped">';
      table_data += '<th>First name</th><th>Last name</th><th>Nickname</th><th>Grade</th>'
      for(var count = 0; count < data.length; count++) {
        table_data += '<tr>';
            table_data += '<td>'+data[count]['Firstname']+'</td>';
            table_data += '<td>'+data[count]['Lastname']+'</td>';
            table_data += '<td>'+data[count]['Nickname']+'</td>';
            table_data += '<td>'+data[count]['Grade']+'</td>';
        table_data += '</tr>';
        }
      table_data += '</table>';
      table_data += '<p><form action="/uploaded" method="post">';
      table_data += 'Does the data look OK? If so, click to upload.  ';
      table_data += '<button class="btn btn-primary" type="submit">Upload</button><p>';
      table_data += '<input type="hidden" id="data" name="data" value='+send_data+'>';
      table_data += '<input type="hidden" name="class_id" value="{{ class_id }}">';
      table_data += '</form>';
      table_data += 'Otherwise, fix the file and reload.';
      document.getElementById("result_table").innerHTML = table_data;
  }
  </script>

【问题讨论】:

  • 您是否使用 AJAX 请求来发送数据? URL 中的空格无效。如果您使用的是 GET 请求,则需要对空格进行编码。最好使用 POST 请求。
  • 非常有趣的 JS。为什么要先替换换行符然后拆分,而不是直接在换行符上拆分。选项卡也是如此。如果有人将 ^^^xyz 作为昵称,这将破坏您的数据。
  • Python 错误是抱怨数据被截断。奇怪的是第 256 个字符。我正要吃晚饭,但那个 JS 似乎只是在记录数据。您能否展示您正在使用的实际 JavaScript 代码。我认为问题可能就在那里。看起来正在使用的最新版本的 papa 解析库具有内置功能,可以替代很多正在发生的事情。
  • 更新帖子以解决一些 cmets。

标签: python json stringify


【解决方案1】:

JavaScript 可以变得更简单。如果您改为执行以下操作,您是否对 JSON 被截断有任何问题?

document.getElementById('update-data-from-file').addEventListener('change', function(evt){
  var file = evt.target.files[0];
  document.getElementById('filename').innerText = file.name

  if (file === "")
    return;

  Papa.parse(file, {
    header: true,
    skipEmptyLines: true,
    complete: function(results) {
      json = results.data
      console.log(json)
      // Do stuff with the json here
    }
  });

  document.getElementById('update-data-from-file').value = ''
})
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.0.2/papaparse.min.js"></script>
  </head>
  <body>

    <label>
      Upload CSV
      <input type="file" name="File Upload" id="update-data-from-file" accept=".csv" />
    </label>
    <div id="filename">No file chosen</div>
    
  </body>
</html>

【讨论】:

  • 这在 JavaScript 方面效果很好,但是当我尝试使用 POST 表单将其移动到 Python 时,我仍然收到相同的 json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 103 (char 102) 错误。当 JSON 在其中一个值中遇到空格时,它仍会在 Python 中中断。
【解决方案2】:

问题在于我发送 JSON 字符串的方式——它不在引号中,所以只要值中有空格,就会出现问题。

修复它:我从上面的答案中得到了 JSON,然后在通过 POST 请求发送 JSON 字符串之前,我将它括在引号中。

send_data = JSON.stringify(json);
send_data = "'" + send_data + "'";

我现在可以发送包含空格的值了。

【讨论】:

  • 很高兴你能弄清楚。
  • 我认为问题实际上出在'&lt;input type="hidden" id="data" name="data" value='+send_data+'&gt;';。诸如id="data" 之类的HTML 属性具有用引号括起来的属性值,允许它们有空格,但是当您使用value='+send_data+' 时,唯一的引号是结束/开始JavaScript 字符串的引号,实际的HTML 将由此产生不会有周围的引号。您的解决方案添加了这些周围的引号。这有意义吗?
  • 问题不在于烧瓶。当你有诸如'&lt;input a="' + 'this works' + '"' + ' b=' + 'this breaks' + ' &gt;' 之类的东西时,它会变成'&lt;input a="this works" b=this breaks &gt;'。 Chrome 现在会将此解释为看到属性a 等于this worksb 将等于this,并且将有第三个属性称为breaks,它不等于任何东西。不是我们想要的。这也是我有时也会犯的错误。很容易错过生成的 HTML 不会在属性值周围加上引号。
  • @hostingutilities.com 是的,这一切都说得通。非常感谢你!我编辑了我的答案以删除对 Flask 的提及。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
  • 2020-08-19
相关资源
最近更新 更多