skip to Main Content

i have this code in php:

$n = '[{"area":30,"ind":[5,5,4,5,4.14,3.75],"isCluster":true},{"area":31,"ind":[],"isCluster":false}]';

$command = ""C:Program FilesRR-4.3.0binRscript.exe" C:\xampp\htdocs\CKmeans1D.R $n";
exec($command, $output);

print_r($output);

it execute the CKmeans1D.R to run R file, and in R i have this code:

library(jsonlite)

args <- commandArgs(trailingOnly = TRUE)

x <- fromJSON(args[1])
x

after printing out the output which is the x it error in the php error logs, and this is the error:

Error: lexical error: invalid char in json text.
                                     [{area:30,ind:[5,5,4,5,4.14,3.75]
                     (right here) ------^
Execution halted

however before adding this line x <- fromJSON(args[1]) i printed out the args[1] and it returns with this:

[{area:30,ind:[5,5,4,5,4.14,3.75],isCluster:true},{area:31,ind:[],isCluster:false}]

the double qoutes are removed in every keys.

how am i able to fix it?

2

Answers


  1. I found a JavaScript code in a gist whose purpose is to fix JSON strings. We can use it with the help of the V8 package to fix your JSON string.

    Firstly, copy the JavaScript code below and save it under the name jsonNormalize.js:

    // https://gist.github.com/dfkaye/dcb060a13470de8119833dc56933563f
    // copyright David Kaye
    
    /**
     * Helper functions and queries for normalize() method.
     */
    
    const BLANK_LINES = /([n](s)*(?:n))/g;
    const LINE_COMMENTS = /["']*(?:[sw]]*)(//[^n^"^}]*)/g;
    // Attempt to handle /* */ and /** javadoc style * line * line2 comments */
    const MULTILINE_COMMENTS = /["']*(?:s*)(/*+)([^*]*[*])([^/]*[/])/g;
    const SINGLE_QUOTES = /([^\]['](?:[^']*)['](?:[^}^:^,]*))/g;
    const UNQUOTED_WORDS = /(?:(,|:|{)s*)([w]+)/g;
    
    function addQuotes(e) {
    
      // return booleans unchanged
      if (/false|true/.test(e)) {
        return e;
      }
    
      // return numbers unchanged
      if (/^d?.?d+$/.test(e)) {
        return e;
      }
    
      // replaces null, undefined, and NaN with empty string
      if (/null|undefined|NaN/.test(e)) {
        e = '';
      }
    
      return '"' + e + '"';
    }
    
    function replaceUnquoted(m) {
      return m.replace(/w+/g, addQuotes);
    }
    
    /**
     * @method normalize Attempts to fix a JSON string with bare keys (restore
     * missing quotes) and single-quoted keys and values, and remove line comments,
     * block comments, blank lines, etc.
     * @param {string} jsonText
     * @returns {string}
     */
    
    function normalize(jsonText) {
      var fixed = jsonText
    
        // 18 Oct 2018 - remove comments and blank lines
        // 30 Oct 2018 - preserve quoted comments
        // remove line comments
        .replace(LINE_COMMENTS, e => {
    
          // Ignore if line comment is quoted.
          return /["']([sw]*[:])?/.test(e[0]) ? e : '';
        })
    
        // remove multi-line comments
        .replace(MULTILINE_COMMENTS, e => {
    
          // Ignore if comment is quoted.
          return /["']/.test(e[0]) ? e : '';
        })
    
        // remove blank lines
        .replace(BLANK_LINES, 'n')
    
        // 17,18 oct 2018
        // fix single quotes
        // 15 feb 2019
        // escaped apostrophes
        .replace(SINGLE_QUOTES, (m) => {
    
          /*
           * Replace leading and trailing single quotes with double quotes, trim
           * quoted spaces, ignore quoted apostrophes.
           */
    
          var t = m.trim();
          var p = m.split(t);
          var r = p[0] + t.replace(/^[']/, '"') + p[1];
    
          return r.replace(/(['])(?:[s]*)$/, (e) => {
            return '"' + (e.length > 1 ? e.substring(1) : '');
          });
        })
    
        // 17 october 2018
        // success
        // add missing quotes
        .replace(UNQUOTED_WORDS, replaceUnquoted)
    
        // 28 December 2019 - fix [01] and { 01: 01 }
        // e.g., replace 01 with "01"
        .replace(/(?=[^"^']+)[0]+([1-9)+(?=[^"^']+)/g, function (e) {
          return '"' + e + '"';
        })
    
        // trim it
        .trim();
    
      return fixed;
    }
    

    Now it is a child game to fix your JSON string with the V8 package:

    x <- "[{area:30,ind:[5,5,4,5,4.14,3.75],isCluster:true},{area:31,ind:[],isCluster:false}]"
    
    library(V8)
    ctx <- v8()
    
    ctx$source("jsonNormalize.js")
    ctx$assign("x", x)
    ctx$eval("var newx = normalize(x);")
    ctx$get("newx")
    # "[{"area":30,"ind":[5,5,4,5,4.14,3.75],"isCluster":true},{"area":31,"ind":[],"isCluster":false}]"
    

    The double quotes are back!

    Maybe this method deserves a small R package. It is useful. Thanks to the author of the gist, David Kaye.


    Edit

    I’ve just done the package

    remotes::install_github("stla/jsonNormalize")
    library(jsonNormalize)
    # the keys of the following JSON string are not quoted
    jstring <- "[{area:30,ind:[5,4.1,3.7],cluster:true},{ind:[],cluster:false}]"
    jsonNormalize(jstring)
    # [1] "[{"area":30,"ind":[5,4.1,3.7],"cluster":true},{"ind":[],"cluster":false}]"
    
    Login or Signup to reply.
  2. When building the command in your PHP code, enclose the JSON string n with single quotes :

    $command = ""C:Program FilesRR-4.3.0binRscript.exe" C:\xampp\htdocs\CKmeans1D.R '$n'";
    

    Testing without PHP, argtest.R :

    jsonlite::fromJSON(commandArgs(trailingOnly = TRUE)[1])
    

    Rscript from command line:

    $ Rscript.exe argtest.R '[{"area":30,"ind":[5,5,4,5,4.14,3.75],"isCluster":true},{"area":31,"ind":[],"isCluster":false}]'
      area                                ind isCluster
    1   30 5.00, 5.00, 4.00, 5.00, 4.14, 3.75      TRUE
    2   31                                        FALSE
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search