6

I can't get replaceAll to work on the '\r\n' sequence in a JSON serialized string.

I am serializing a Map object that contains long textarea fields with newlines. I need to change '\r\n' to '\\r\\n' for Javascript purposes. When I serialize the object, I see '\r\n' in the resulting string. However, none of the replaceAll lines that I try will work:

Map<Id, Job_Posting__c> jobMap = new Map<Id, Job_Posting__c>();
// job map gets populated.
String x = JSON.serialize(jobMap);
String y = x.replaceAll('\r\n', '\\r\\n');
String z = x.replaceAll('\\r\\n', '\\\\r\\\\n');

Is there something about JSON serialized strings that force a different approach? I see that the serialized string is between double quotes - does that make a difference?

Details: I want to pass a serialized map of job posting records to a Javascript function in a Visualforce page. The Javascript JSON.parse() fails with "unexpected token" when it hits the '\r\n'. If I manually edit the JSON string to be '\\r\\n' then the parse works.

Here's the Javascript on the VF page:

<script>
    // Define the CCx.pageJobSelection module - can be moved to static resource
    (function (module, $) {
        "use strict";
        var data_jobPostings;

        // intercept the 'submit' action of the HTML form 
        jQuery(document).ready( function ($) {
            //processing here.
        });

        module.initialize = function (options) {
            data_jobPostings = JSON.parse(options.jobPostings);
        };

    })(CCx.pageJobSelection = CCx.pageJobSelection || {}, jQuery);

    // initialize the module
    CCx.pageJobSelection.initialize({
        jobPostings: '{!jobMapJSON}'
    })

</script>

Here's the VF controller:

public with sharing class HL_CCx_JobSelectionController {
    public String jobMapJSON { get; private set; }
    public List<Job_Posting__c> jobs { get; private set; }
    private Map<Id, Job_Posting__c> jobMap = new Map<Id, Job_Posting__c>();

    // Constructor
    public HL_CCx_JobSelectionController() {
        jobs = CCx_JobSelector.selectActiveJobs();
        if (jobs == null) {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 'No jobs postings available.'));
            return;
        }

        jobMap.putAll(jobs);

        // Serialize
        jobMapJSON = JSON.serialize(jobMap);
        jobMapJSON = jobMapJSON.replaceAll('\r\n', '\\r\\n');
    }
}
6
  • Can you explain a bit more why you want to do this replacement? JSON supports \r\n and most JSON is valid JavaScript too.
    – Keith C
    Jun 16, 2014 at 16:49
  • @KeithC - I added some explanation to the original post, thanks. Jun 16, 2014 at 17:04
  • Once you have an apex string, it shouldn't matter where the string came from. What happens if you do this: (a) get the serialized JSON string from this controller, copy to clipboard, (b) run in anonymous window: String j = 'STRING FROM FIRST STEP'; System.debug(j.replaceAll('\r\n', '\\r\\n');
    – Benj
    Jun 16, 2014 at 17:27
  • Alternatively, what if you make the replacement in javascript? data_jobPostings = JSON.parse( options.jobPostings.replace(/\r\n/g, '\\r\\n') );
    – Benj
    Jun 16, 2014 at 17:30
  • When I do that in Apex I get 'rn', when I do the replace in Javascript I don't get any errors, but there's no line break between the text lines. Jun 16, 2014 at 18:21

2 Answers 2

4

Why not just emit the JSON into the page so it is immediately parsed by JavaScript:

CCx.pageJobSelection.initialize(
    {!jobMapJSON}
);

and then there is no need to parse yourself:

module.initialize = function (options) {
    data_jobPostings = options;
};

This should avoid the need for any replacing.

Its also worth using JSON.serializePretty to make the JSON easier to manually review when you do a "View Page Source" of the page.

PS

This page:

<apex:page controller="AbcController">
<script>
var map = {!jsonString};
alert(map);
</script>
</apex:page>

and controller (where cve__OccupationalDescription__c is a custom text area field):

public class AbcController {
    public String jsonString {
        get {
            return JSON.serializePretty(new Map<Id, Contact>([
                    select Id, FirstName, LastName, cve__OccupationalDescription__c
                    from Contact
                    limit 2
                    ]));
        }
    }
}

produce this valid JSON that the browser's JavaScript engine is happy with:

<script>
var map = {
  "003A000000ou3XLIAY" : {
    "attributes" : {
      "type" : "Contact",
      "url" : "/services/data/v30.0/sobjects/Contact/003A000000ou3XLIAY"
    },
    "cve__OccupationalDescription__c" : "Line 1.\r\nLine 2.\r\nLine 3.",
    "RecordTypeId" : "012A0000000zC62IAE",
    "FirstName" : "Tim",
    "Id" : "003A000000ou3XLIAY",
    "LastName" : "Jones"
  },
  "003A000000pm2plIAA" : {
    "attributes" : {
      "type" : "Contact",
      "url" : "/services/data/v30.0/sobjects/Contact/003A000000pm2plIAA"
    },
    "RecordTypeId" : "012A0000000zC62IAE",
    "FirstName" : "Derek",
    "Id" : "003A000000pm2plIAA",
    "LastName" : "O'Brien"
  }
};
alert(map);
</script>
5
  • if the OP wants to pass in an options object (rather than a single data value), it could also work like this: CCx.pageJobSelection.initialize( options = data_jobPostings: {!jobMapJSON} );
    – Benj
    Jun 16, 2014 at 17:58
  • If I try just {!jobMapJSON} or options = data_jobPostings: {!jobMapJSON}, I get unexpected token errors. Jun 16, 2014 at 18:19
  • @DavidCheng Perhaps you can post what "View Page Source" shows you and the specific error message? I just added a working example to the answer.
    – Keith C
    Jun 16, 2014 at 18:51
  • Thanks, I went back to your original code snippets and it worked. I had extra curly braces in the initialize method that caused the unexpected token error. Jun 16, 2014 at 20:04
  • That's a nice workaround but I wish there was an answer to the question of why \r\n can't be replaced in JSON
    – Alkanshel
    Jan 26, 2019 at 0:10
-1
final String CRLF = '\r\n';

String x = '\r\n';
String expected = '\\r\\n';

System.assertEquals(expected, x.replaceAll(CRLF, '\\\\r\\\\n'));
1
  • Alan - if you serialize x, then it doesn't work. Jun 16, 2014 at 17:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .