字符串中需要多个匹配项的.replace()替换函数的替代方案。

huangapple go评论54阅读模式
英文:

Alternative to .replace() replacer function needed for multiple matches in a string

问题

.matchAll() is a suitable alternative to .replace() in this case for extracting matched substrings, and it can simplify your code. However, there's a difference in the output format between the two examples you provided. The first example extracts and pushes substrings and arrays into the results array, while the second example directly extracts and returns an array of matched substrings using .matchAll().

If you want the output to match the format of the first example, where substrings and arrays are pushed into an array, you would need to modify the second example accordingly. Here's how you can achieve that:

const scan = (str, pattern) => {
  return [...str.matchAll(pattern)].map((match) => {
    const results = Array.prototype.slice.call(match, 1, -2);
    return results.length === 1 ? results[0] : results;
  });
}

With this modification, the output will be structured similarly to the first example.

英文:

I'm working on a project that does some string parsing (for a song lyrics format) and I ran across a usage of the .replace() method that feels a bit hacky to me... but it does work.

This is how it currently works right now, and it logs out the expected result.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const scan = (str, pattern) =&gt; {
  const results = [];

  str.replace(pattern, function() {
    results.push(Array.prototype.slice.call(arguments, 1, -2));
  });

  return _.flatten(results)
}

console.log(&quot;Lyrics&quot;, scan(
  &quot;I don&#39;t see! a bad, moon a-rising. (a-rising)&quot;,
  /(\[[\w#b/]+])?([\w\s&#39;,.!()_\-&quot;]*)/gi
));

console.log(&quot;Chords&quot;, scan(
  &quot;[D] [D/F#] [C] [A7]&quot;,
  /\[([\w#b+/]+)]?/gi
));

console.log(&quot;Measures&quot;, scan(
  `
# Instrumental

| [A] [B] | [C] | [D] [E] [F] [G] |
`,
  /([[\w#b/\]+\]\s]+)[|]*/gi
));

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js&quot; integrity=&quot;sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

The usage of .replace() feels wrong since it's not actually doing any replacing but relying on the looping behavior to push items into an array. That returns an array with a single item, of an array of strings. Lodash is then used to flatten it out into a single string array.

I feel like this could be improved to use .matchAll() instead, but I haven't been able to get it quite right just yet. Here's what I have so far, which works but the output is wrong since it's not identical to the above example.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const scan = (str, pattern) =&gt; {
  return [...str.matchAll(pattern)].map(r=&gt;{
    return r[1]
});
}

console.log(&quot;Lyrics&quot;, scan(
  &quot;I don&#39;t see! a bad, moon a-rising. (a-rising)&quot;,
  /(\[[\w#b/]+])?([\w\s&#39;,.!()_\-&quot;]*)/gi
));

console.log(&quot;Chords&quot;, scan(
  &quot;[D] [D/F#] [C] [A7]&quot;,
  /\[([\w#b+/]+)]?/gi
));

console.log(&quot;Measures&quot;, scan(
  `
# Instrumental

| [A] [B] | [C] | [D] [E] [F] [G] |
`,
  /([[\w#b/\]+\]\s]+)[|]*/gi
));

<!-- end snippet -->

Is .matchAll() the correct alternative to .replace() in this case? Is there a better way to get the desired output instead of what I am currently doing? I know I'm currently not calling the .slice() method that the first example has yet because I'm not entirely sure I understand what this is trying to accomplish here since this code was not originally written by me.

答案1

得分: 0

You can use flatMap and slice.

const pattern = /(\[[\w#b/]+])?([\w\s&#39;,.!()_\-&quot;]*)/gi;
const str = &quot;I don&#39;t see! a bad, moon a-rising. (a-rising)&quot;

const results =  [...str.matchAll(pattern)].flatMap(m =&gt; m.slice(1));

console.log(&#39;results&#39;, results)

(Note: I've kept the code portion in its original format, including HTML entities like &quot; and &gt;. If you want those entities translated, please let me know.)

英文:

You can use flatMap and slice.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const pattern = /(\[[\w#b/]+])?([\w\s&#39;,.!()_\-&quot;]*)/gi;
const str = &quot;I don&#39;t see! a bad, moon a-rising. (a-rising)&quot;;

const results =  [...str.matchAll(pattern)].flatMap(m =&gt; m.slice(1));

console.log(&#39;results&#39;, results)

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月23日 00:33:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76308248.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定