简体   繁体   中英

In a string get everything before and after the substring

I'm working in angular trying to create a logic for Fill in the blanks where the user can input text in textarea and then make as many blanks as they want from a sentence.

For example: "This is a bowl of fruit"

If the user decides to make "bowl" as a blank they simply would put 2 brackets around it or click on a button and the above sentence would be changed to

"This is a [[bowl]] of fruit."

To do this I've the following code if the user decides to select the word and click on button to make the blank.

html.component

   <textarea (ngModel)]="blankText" #blankArea rows="4" cols="50"></textarea>
   <button class="btn btn-link" (click)="makeBlank(blankArea.selectionStart, blankArea.selectionEnd)">Make Blank</button>

component.ts

  makeBlank(start, end) {
    this.blankStatement = [];
    let result;
    let sentence = this.blankText;
    let blankStart = '[[';
    let blankEnd = ']]';

    result = sentence.slice(0, start) + blankStart + sentence.slice(start);
    end = end + 2;
    result = result.slice(0, end) + blankEnd + result.slice(end);
    this.blankText = result;

    //Get Blank Data
    var part = result.substring(
      result.lastIndexOf('[[') + 2,
      result.lastIndexOf(']]')
    );
    let obj = {
      blank: part,
    };
    this.blanks.push(obj); //This saves the blank word i.e "Bowl"
   
  }

What I'm trying to achieve is to get data in the following format:

blankStatement = 
[ 
{type: "Text", text: "This is a"}, 
{type: "Word", blank:"bowl"}, 
{type:"Text", text:"of fruit"}
]

The text before the blank and after the blank is type: Text. The text in the blank is type: "Word". I'm able to get the text before and after the blank as:

let preText = this.blankText.substring(0, preText.indexOf('['));
let postText = this.blankText.split(']').pop();

Issue

If I make another blank lets say from the sentence "This is a [[bowl]] of Fruit" I make "Fruit" as a blank too, This is a [[bowl]] of [[Fruit]]. Then how can I achieve the following array:

 blankStatement = 
[ 
{type: "Text", text: "This is a"}, 
{type: "Word", blank:"bowl"}, 
{type: "Text", text:"of"},
{type: "Word", blank:"fruit" }
]

You could use .matchAll() with a regular expression to match all occurrences of [[ and ]] . This is done using a regular expression, which also groups the text inside of the square brackets. The .matchAll() method gives back an iterator, which you can then turn into an array using the spread syntax ... . The elements in the array contain the match and the group in the zero-th and first index of the array, which you can pull out using destructuring assignment . You can also pull out other properties such as the index at which the match occurred. Using this, you can work out the text between each match, and then add that to your resulting array. You can then perform a filter to remove any object that contains an empty from your result. See example below:

 const str = "This is a [[bowl]] of [[Fruit]]"; const getWordsAndText = (str) => { const matches = [...str.matchAll(/\[\[([^\]\]]+)\]\]/g)]; let lastIndex = 0; return matches.flatMap(({0: match, 1: blank, index, input}) => { const arr = [ {type: "Text", text: input.substring(lastIndex, index).trim()}, {type: "Word", blank: blank.toLowerCase()} ]; lastIndex = index + match.length; return arr; }).concat({type: "Text", text: str.substring(lastIndex).trim()}).filter(({text}) => text;== ""). } console;log(getWordsAndText(str));

If you need to optimize this, you could be more considerate about what you return from the .flatMap() , that way, you won't need to perform a second iteration over your result to filter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM