Split() function not working

I have a .csv file that I'm calling in JavaScript through a p5.js sketch. One of the fields contains sentences that range from 103 char to 328 char. My script calls the data and displays in randomly on the canvas. Because some of the sentences are very long, they aren't fitting on the canvas properly, so I'd like to split them into 2- or 3-line strings.

I won't post my whole code, but here is the setup() snippet:

function setup() {
  canvas = createCanvas(680, 420);
  canvas.mousePressed(inWidth);
  background(51);
  // Calling noStroke once here to avoid unecessary repeated function calls
  noStroke();
  // iterate over the table rows
  for (var i = 0; i < clContext.getRowCount(); i++) {
    var category = clContext.get(i, "category");
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity");

 // split long statements that have '\r\n' in them and add the rest as a second or third line
    statement = split(statement, "[\\r\\n]+");

 // creates `display()` object from `Statement` constructor (not shown)
    statements[i] = new Statement(category, polarity, statement);
  }
}

I have tried various configurations based on native js, e.g., var array = sentence.split("\n").map(x => x.trim());, but that just throws an error that sentence.split is not a function. And now I've tried what's there now, including putting it in a for loop, from the Processing reference, but I have not found a solution that works. I can still run the sketch, but the line breaks don't work.

Answers

  • Check that sentence is of type String and if necessary explicitly cast it as a String before calling split:

    String(sentence).split("\n");
    

    And you might alternatively use String methods such as substr, using indexOf to find a suitable new line to split on...

  • Thanks, @blindfish. I tried your code example, but it didn't do the trick. I've spent hours and hours reading the native js methods for splitting and have tried several solutions, none of which have worked.

    I'm not sure how to implement indexOf in this case as the documentation says it returns a value based on whether the string is found. For example, one of the long sentences I have is:

    You stand up and always have against gun violence, advocate for criminal justice reform, help young people find jobs,  hold corporations accountable, and in a million ways, lift up voices that too often go unheard.
    

    So, suppose I want the split to be between "jobs" and "hold" in the middle, how would I do that? I need it to split multiple sentences from the .csv file, so what I was trying to do is mark off where the split should be in the .csv file. So the above sentence would look like this in the .csv file:

    You stand up and always have against gun violence, advocate for criminal justice reform, help young people find jobs, \r\n hold corporations accountable, and in a million ways, lift up voices that too often go unheard.
    

    Then I would tell the RegExp to look for "\r\n" and split there and add the remainder as the next line. It's not clear to me from the documentation how to do that with substr and indexOf.

  • Hi @GoToLoop. Yes, that's my question. Wondering why you posted the link to it.

  • I thought folks would like to follow what's happening out there too. ;;)

  • Ah. Got it! Thanks!

  • Hmmm - I hope your issue is nothing to do with the fact that your variable name is 'statement' but your example of split uses the variable name 'sentence' :(|)

    Otherwise it could perhaps be an issue with p5's split method. I've no need to touch the DOM library so don't have much interest in pursuing that line of inquiry.

    In the meantime here's a thrown together demo of a native JS function that will split a string based on a desired target length:

    "use strict";
    
    var clContext;
    
    function preload() {
            clContext = loadTable("cl_context.csv", "header");
    }
    
    function setup() {
      canvas = createCanvas(680, 420);
      for (var i = 0; i < clContext.getRowCount(); i++) {
        var statement = clContext.get(i, "statement");
    
        console.log(splitStringAtSpace(statement, 50));
      }
    }
    
    
    function splitStringAtSpace(input, desiredLength) {
        // cast to String
        var inputString = String(input);
        var inputLength = inputString.length;
        // estimate of number of splits required 
        var divisions = Math.floor(inputLength/desiredLength);
        var segments = [];
        var lastIndex = 0;
        var nextIndex = 0;
    
        for(var i=0; i<divisions; i++) {
            // find the index of the next space after the desired string length
            nextIndex = inputString.indexOf(" ", lastIndex + desiredLength);
            // take account of end of string
            nextIndex = nextIndex > -1 ? nextIndex : inputLength;
    
            var segment = inputString.substring(lastIndex, nextIndex).trim();
    
            if(segment) {
                segments.push(segment);    
            }
    
            lastIndex = nextIndex;
        }
    
        return(segments);
    
    }
    

    There are almost certainly more elegant ways of doing this; and there's already one obvious problem: your text contains HTML tags that aren't excluded from the character count so those lines will land up shorter when rendered.

    ...But if you're willing to do the donkey work of placing split tokens in your data then this task really should be trivial and not require any complex string manipulation.

  • Just to back up that last point here's an example splitting based on the <br> tags in your data:

    "use strict";
    
    var clContext;
    
    function preload() {
      clContext = loadTable("cl_context.csv", "header");
    }
    
    function setup() {
      canvas = createCanvas(680, 420);
      for (var i = 0; i < clContext.getRowCount(); i++) {
        var statement = clContext.get(i, "statement");  
        console.log(statement.split("<br>"));
      }
    }
    
  • Hi @blindfish, Thanks for those suggestions. Unfortunately, they didn't do the trick. I tried your second suggestion first and then added the function from the first suggestion and tried running it that way. What happens with the first function is that the console shows split statements, but the actual p5 sketch display does not. They're still all one line statements. Nothing happens with the console.log(statement.split("<br>")); suggestion. The console shows no split.

    I'm VERY new to JavaScript, so forgive a stupid question. You use console.log() in both suggestions. I was under the impression that console.log() is merely a way to help debug a program in the developer console and not a method that runs what's inside the parentheses. I'm assuming that, since you used it, I must be wrong about that, yes?

  • @ console.log(statement.split("<br>"));, statement.split("<br>") is the argument passed to method log(), in the same way that "<br>" is the argument for method split().

    Once split() is resolved, its returned value becomes the argument for method log().

    According to String's split() reference, that returning value is an array of strings:
    https://developer.Mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split

    Thus log() is gonna display the String content of that array at the console.

  • @ldlpdx console.log is a useful tool for debugging and demonstrating code. I used it to show that split() should be adequate for your purposes.

    As @GoToLoop says statement.split("<br>") is the code that breaks the input string into an array. That's what the console shows when you run my code: a series of arrays of differing length depending on how many <br> tags there are in your data. There's nothing in the code to output it to the sketch: you can only expect us to do so much :P

    You will have to work with the returned array to get the output you desire; presumably by passing it into your statement object; either as an array or combined into a single string with a suitable delimiter to produce line breaks in the output. For the latter the join method is likely to be useful ;)

  • @ldlpdx Glad to hear from your other post that you are making progress. The slight problem with posting this question in isolation from your other code is we don't see, and can't test, the context in which you want it displayed.

    If the text is going into a canvas element you either need to add a delimiter that generates a line break (assuming such a delimiter exists) or to manually render each element from the array at a different y position...

  • edited June 2016

    Thanks, @blindfish. I've apparently caused some confusion, and probably frustration. First, as I said above, statement.split("<br>") does nothing to break apart the statements. It's the function you kindly wrote that does so.

    And as for...

    There's nothing in the code to output it to the sketch: you can only expect us to do so much.  
    

    I do actually have a draw() function that calls the statements from statements[i] = new Statement(polarity, statement); from setup(), I just didn't include it in an effort to reduce what people had to go through to figure out what I need, which is something that allows me to break up the statements and display them on multiple lines in the sketch.

    My complete script for this is more than 100 lines, and I once got nailed for posting an entire script when I just needed help with something specific. I apologize if I've caused frustration.

  • @ldlpdx you haven't caused frustration so no need to apologise. I also appreciate it's sometimes hard to judge how much code to post! Some would have you write a simplified version of your code for the purposes of the forum... That can be painful; but can sometimes also help isolate the cause of a problem.

    Since you've got this on github I'd suggest in future you post the snippet you think is relevant to the forum and also link through to the full/current version of the code. I had of course assumed you had some draw code somewhere; but I could only provide advice based on the code I had access to ;)

    Re:

    First, as I said above, statement.split("<br>") does nothing to the statements. It's the function you kindly wrote that does so.

    Assuming I'm looking at the same data splitting on break tags definitely splits some of your data into multi-element arrays...

Sign In or Register to comment.