简体   繁体   中英

Trim specific character from a string

What's the JavaScript equivalent to this C# Method:

var x = "|f|oo||"; 
var y = x.Trim('|'); //  "f|oo"

C# trims the selected character only at the beginning and end of the string!

One line is enough:

 var x = '|f|oo||'; var y = x.replace(/^\\|+|\\|+$/g, ''); document.write(x + '<br />' + y);

^     beginning of the string
\|+   pipe, one or more times
|     or
\|+   pipe, one or more times
$     end of the string

A general solution:

 function trim (s, c) { if (c === "]") c = "\\\\]"; if (c === "^") c = "\\\\^"; if (c === "\\\\") c = "\\\\\\\\"; return s.replace(new RegExp( "^[" + c + "]+|[" + c + "]+$", "g" ), ""); } chars = ".|]\\\\^"; for (c of chars) { s = c + "foo" + c + c + "oo" + c + c + c; console.log(s, "->", trim(s, c)); }

Parameter c is expected to be a character (a string of length 1).

As mentionned in the comments, it might be useful to support multiple characters, as it's quite common to trim multiple whitespace-like characters for example. To do this, MightyPork suggests to replace the if s with the following line of code:

c = c.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');

This part [-/\\\\^$*+?.()|[\\]{}] is a set of special characters in regular expression syntax, and $& is a placeholder which stands for the matching character, meaning that the replace function escapes special characters. Try in your browser console:

> "{[hello]}".replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
"\{\[hello\]\}"

If I understood well, you want to remove a specific character only if it is at the beginning or at the end of the string (ex: ||fo||oo|||| should become foo||oo ). You can create an ad hoc function as follows:

function trimChar(string, charToRemove) {
    while(string.charAt(0)==charToRemove) {
        string = string.substring(1);
    }

    while(string.charAt(string.length-1)==charToRemove) {
        string = string.substring(0,string.length-1);
    }

    return string;
}

I tested this function with the code below:

var str = "|f|oo||";
$( "#original" ).html( "Original String: '" + str + "'" );
$( "#trimmed" ).html( "Trimmed: '" + trimChar(str, "|") + "'" );

Update: Was curious around the performance of different solutions and so I've updated a basic benchmark here: https://www.measurethat.net/Benchmarks/Show/12738/0/trimming-leadingtrailing-characters

Some interesting and unexpected results running under Chrome. https://www.measurethat.net/Benchmarks/ShowResult/182877

+-----------------------------------+-----------------------+
| Test name                         | Executions per second |
+-----------------------------------+-----------------------+
| Index Version (Jason Larke)       | 949979.7 Ops/sec      |
| Substring Version (Pho3niX83)     | 197548.9 Ops/sec      |
| Regex Version (leaf)              | 107357.2 Ops/sec      |
| Boolean Filter Version (mbaer3000)| 94162.3 Ops/sec       |
| Spread Version (Robin F.)         | 4242.8 Ops/sec        |
+-----------------------------------+-----------------------+

Please note; tests were carried out on only a single test string (with both leading and trailing characters that needed trimming). In addition, this benchmark only gives an indication of raw speed; other factors like memory usage are also important to consider.


If you're dealing with longer strings I believe this should outperform most of the other options by reducing the number of allocated strings to either zero or one:

function trim(str, ch) {
    var start = 0, 
        end = str.length;

    while(start < end && str[start] === ch)
        ++start;

    while(end > start && str[end - 1] === ch)
        --end;

    return (start > 0 || end < str.length) ? str.substring(start, end) : str;
}

// Usage:
trim('|hello|world|', '|'); // => 'hello|world'

Or if you want to trim from a set of multiple characters:

function trimAny(str, chars) {
    var start = 0, 
        end = str.length;

    while(start < end && chars.indexOf(str[start]) >= 0)
        ++start;

    while(end > start && chars.indexOf(str[end - 1]) >= 0)
        --end;

    return (start > 0 || end < str.length) ? str.substring(start, end) : str;
}

// Usage:
trimAny('|hello|world   ', [ '|', ' ' ]); // => 'hello|world'
// because '.indexOf' is used, you could also pass a string for the 2nd parameter:
trimAny('|hello| world  ', '| '); // => 'hello|world'

EDIT: For fun, trim words (rather than individual characters)

// Helper function to detect if a string contains another string
//     at a specific position. 
// Equivalent to using `str.indexOf(substr, pos) === pos` but *should* be more efficient on longer strings as it can exit early (needs benchmarks to back this up).
function hasSubstringAt(str, substr, pos) {
    var idx = 0, len = substr.length;

    for (var max = str.length; idx < len; ++idx) {
        if ((pos + idx) >= max || str[pos + idx] != substr[idx])
            break;
    }

    return idx === len;
}

function trimWord(str, word) {
    var start = 0,
        end = str.length,
        len = word.length;

    while (start < end && hasSubstringAt(str, word, start))
        start += word.length;

    while (end > start && hasSubstringAt(str, word, end - len))
        end -= word.length

    return (start > 0 || end < str.length) ? str.substring(start, end) : str;
}

// Usage:
trimWord('blahrealmessageblah', 'blah');

A regex-less version which is easy on the eye:

const trim = (str, chars) => str.split(chars).filter(Boolean).join(chars);

For use cases where we're certain that there's no repetition of the chars off the edges.

You can use a regular expression such as:

var x = "|f|oo||";
var y = x.replace(/^\|+|\|+$/g, "");
alert(y); // f|oo

UPDATE:

Should you wish to generalize this into a function, you can do the following:

var escapeRegExp = function(strToEscape) {
    // Escape special characters for use in a regular expression
    return strToEscape.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
};

var trimChar = function(origString, charToTrim) {
    charToTrim = escapeRegExp(charToTrim);
    var regEx = new RegExp("^[" + charToTrim + "]+|[" + charToTrim + "]+$", "g");
    return origString.replace(regEx, "");
};

var x = "|f|oo||";
var y = trimChar(x, "|");
alert(y); // f|oo

to keep this question up to date:

here is an approach i'd choose over the regex function using the ES6 spread operator.

function trimByChar(string, character) {
  const first = [...string].findIndex(char => char !== character);
  const last = [...string].reverse().findIndex(char => char !== character);
  return string.substring(first, string.length - last);
}

Improved version after @fabian 's comment (can handle strings containing the same character only)

 function trimByChar1(string, character) { const arr = Array.from(string); const first = arr.findIndex(char => char !== character); const last = arr.reverse().findIndex(char => char !== character); return (first === -1 && last === -1) ? '' : string.substring(first, string.length - last); }

This can trim several characters at a time:

function trimChars (str, c) {
  var re = new RegExp("^[" + c + "]+|[" + c + "]+$", "g");
  return str.replace(re,"");
}

var x = "|f|oo||"; 
x =  trimChars(x, '|'); // f|oo

var y = "..++|f|oo||++..";
y = trimChars(y, '|.+'); // f|oo

var z = "\\f|oo\\"; // \f|oo\

// For backslash, remember to double-escape:
z = trimChars(z, "\\\\"); // f|oo

For use in your own script and if you don't mind changing the prototype, this can be a convenient "hack":

String.prototype.trimChars = function (c) {
  var re = new RegExp("^[" + c + "]+|[" + c + "]+$", "g");
  return this.replace(re,"");
}

var x = "|f|oo||"; 
x =  x.trimChars('|'); // f|oo

Since I use the trimChars function extensively in one of my scripts, I prefer this solution. But there are potential issues with modifying an object's prototype .

Regex seems a bit too complex for a simple problem like Trim?

C#

var x = "|f|oo||"; 
var y = x.Trim('|'); //  "f|oo"

Javascript, x.TrimLeft('|') example - simple (but trims only single character)

 var ltrim = "|"; var x = "|f|oo||"; var y = (x.startsWith(ltrim) ? x.substring(ltrim.length) : x); // "f|oo||" var result = y; console.log(y); 

Javascript full example (thanks to @Tobo answer and @rooby suggestion)

 class SutString extends String { // [S]tring[Ut]ility replaceFirstOnly(src, dest) { return new SutString(this.replace(src, dest)); // String.replace is misleading } replaceAll(src, dest) { return new SutString(this.split(src).join(dest)); } reverse() { return new SutString(this.split("").reverse().join("")); } trimStart(delimiter = " ") { if (!delimiter) { return this.replace(/^\\s+/gm, ''); } var current = this; var index = this.length; while(current.startsWith(delimiter) && index >= 0) { current = current.substring(delimiter.length); --index; } if (typeof(current) === 'string') { return new SutString(current); } return current; }; trimEnd(delimiter = " ") { if (!delimiter) { return new SutString(this.reverse().replace(/^\\s+/gm, '')).reverse(); } var current = this; var index = this.length; while(current.endsWith(delimiter) && index >= 0) { current = current.substring(0, this.length - delimiter.length - 1); --index; } if (typeof(current) === 'string') { return new SutString(current); } return current; }; trimString(delimiter = " ") { if (!delimiter) { return this.trim(); } return this.trimStart(delimiter).trimEnd(delimiter); }; } // Pushes all functions and properties from String to SutString, // returning SutString if the result is a string for(let prop of Object.getOwnPropertyNames(String.prototype)) { if (prop === "constructor" || prop === "toString" || (""[prop]) instanceof Function) { continue; } let newprop = prop; if (typeof(SutString.prototype[prop]) !== 'undefined') { newprop = "base_" + prop; } SutString.prototype[newprop] = function() { const result = this.toString()[prop].apply(this, arguments); if (typeof(result) !== 'string') { return result; } return new SutString(result); } } var str = new SutString("|f|oo||"); var strWhitespace = new SutString(" |f|oo|| "); console.log("\\"" + str.trimStart("|") + "\\" ===", "\\"" + str + "\\".trimStart(\\"|\\");"); console.log("\\"" + str.trimEnd("|") + "\\" ===", "\\"" + str + "\\".trimEnd(\\"|\\");"); console.log("\\"" + str.trimString("|") + "\\" ===", "\\"" + str + "\\".trimString(\\"|\\");"); console.log("\\"" + strWhitespace.trimStart() + "\\" ===", "\\"" + strWhitespace + "\\".trimStart();"); console.log("\\"" + strWhitespace.trimEnd() + "\\" ===", "\\"" + strWhitespace + "\\".trimEnd();"); console.log("\\"" + strWhitespace.trimString() + "\\" ===", "\\"" + strWhitespace + "\\".trimString();"); 

I was a little lazy with trimStart and trimEnd. It would be more efficient to find how much of each side needs trimmed. Then call substring only once. But hopefully you get the idea and this is helpful!

Note: This is es6 specific. Some of this may be implemented for you in es2019.

If you define these functions in your program, your strings will have an upgraded version of trim that can trim all given characters:

 String.prototype.trimLeft = function(charlist) { if (charlist === undefined) charlist = "\\s"; return this.replace(new RegExp("^[" + charlist + "]+"), ""); }; String.prototype.trim = function(charlist) { return this.trimLeft(charlist).trimRight(charlist); }; String.prototype.trimRight = function(charlist) { if (charlist === undefined) charlist = "\\s"; return this.replace(new RegExp("[" + charlist + "]+$"), ""); }; var withChars = "/-center-/" var withoutChars = withChars.trim("/-") document.write(withoutChars)

Source

https://www.sitepoint.com/trimming-strings-in-javascript/

const trim = (str, char) => {
    let i = 0;
    let j = str.length-1;
    while (str[i] === char) i++;
    while (str[j] === char) j--;
    return str.slice(i,j+1);
}
console.log(trim('|f|oo|', '|')); // f|oo

Non-regex solution. Two pointers: i (beginning) & j (end). Only move pointers if they match char and stop when they don't. Return remaining string.

This one trims all leading and trailing delimeters

const trim = (str, delimiter) => {
  const pattern = `[^\\${delimiter}]`;
  const start = str.search(pattern);
  const stop = str.length - str.split('').reverse().join('').search(pattern);
  return str.substring(start, stop);
}

const test = '||2|aaaa12bb3ccc|||||';
console.log(trim(test, '|')); // 2|aaaa12bb3ccc

I would suggest looking at lodash and how they implemented the trim function.

See Lodash Trim for the documentation and the source to see the exact code that does the trimming.

I know this does not provide an exact answer your question, but I think it's good to set a reference to a library on such a question since others might find it useful.

The best way to resolve this task is (similar with PHP trim function):

 function trim( str, charlist ) { if ( typeof charlist == 'undefined' ) { charlist = '\\\\s'; } var pattern = '^[' + charlist + ']*(.*?)[' + charlist + ']*$'; return str.replace( new RegExp( pattern ) , '$1' ) } document.getElementById( 'run' ).onclick = function() { document.getElementById( 'result' ).value = trim( document.getElementById( 'input' ).value, document.getElementById( 'charlist' ).value); }
 <div> <label for="input">Text to trim:</label><br> <input id="input" type="text" placeholder="Text to trim" value="dfstextfsd"><br> <label for="charlist">Charlist:</label><br> <input id="charlist" type="text" placeholder="Charlist" value="dfs"><br> <label for="result">Result:</label><br> <input id="result" type="text" placeholder="Result" disabled><br> <button type="button" id="run">Trim it!</button> </div>

PS: why i posted my answer, when most people already done it before? Because i found "the best" mistake in all of there answers: all used the '+' meta instead of '*', 'cause trim must remove chars IF THEY ARE IN START AND/OR END, but it return original string in else case.

expanding on @leaf 's answer, here's one that can take multiple characters:

var trim = function (s, t) {
  var tr, sr
  tr = t.split('').map(e => `\\\\${e}`).join('')
  sr = s.replace(new RegExp(`^[${tr}]+|[${tr}]+$`, 'g'), '')
  return sr
}

I like the solution from @Pho3niX83...

Let's extend it with "word" instead of "char"...

function trimWord(_string, _word) {

    var splitted = _string.split(_word);

    while (splitted.length && splitted[0] === "") {
        splitted.shift();
    }
    while (splitted.length && splitted[splitted.length - 1] === "") {
        splitted.pop();
    }
    return splitted.join(_word);
};
function trim(text, val) {
    return text.replace(new RegExp('^'+val+'+|'+val+'+$','g'), '');
}
"|Howdy".replace(new RegExp("^\\|"),"");

(note the double escaping. \\\\ needed, to have an actually single slash in the string , that then leads to escaping of | in the regExp ).

Only few characters need regExp-Escaping. , among them the pipe operator.

 const special = ':;"<>?/!`~@#$%^&*()+=-_ '.split(""); const trim = (input) => { const inTrim = (str) => { const spStr = str.split(""); let deleteTill = 0; let startChar = spStr[deleteTill]; while (special.some((s) => s === startChar)) { deleteTill++; if (deleteTill <= spStr.length) { startChar = spStr[deleteTill]; } else { deleteTill--; break; } } spStr.splice(0, deleteTill); return spStr.join(""); }; input = inTrim(input); input = inTrim(input.split("").reverse().join("")).split("").reverse().join(""); return input; }; alert(trim('@#This is what I use$%'));

Another version to use regular expression.

No or( | ) used and no global( g ) used.

 function escapeRegexp(s) { return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } function trimSpecific(value, find) { const find2 = escapeRegexp(find); return value.replace(new RegExp(`^[${find2}]*(.*?)[${find2}]*$`), '$1') } console.log(trimSpecific('"a"b"', '"') === 'a"b'); console.log(trimSpecific('""ab"""', '"') === 'ab'); console.log(trimSpecific('"', '"') === ''); console.log(trimSpecific('"a', '"') === 'a'); console.log(trimSpecific('a"', '"') === 'a'); console.log(trimSpecific('[a]', '[]') === 'a'); console.log(trimSpecific('{[a]}', '[{}]') === 'a');

To my knowledge, jQuery doesnt have a built in function the method your are asking about. With javascript however, you can just use replace to change the content of your string:

x.replace(/|/i, ""));

This will replace all occurences of | with nothing.

String.prototype.TrimStart = function (n) {
    if (this.charAt(0) == n)
        return this.substr(1);
};

String.prototype.TrimEnd = function (n) {
    if (this.slice(-1) == n)
        return this.slice(0, -1);
};

尝试:

console.log(x.replace(/\|/g,''));

Try this method:

 var a = "anan güzel mi?"; if (a.endsWith("?")) a = a.slice(0, -1); document.body.innerHTML = a;

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