从字符串中删除特定字符

什么是JavaScript相当于这个C#方法:

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

C#只在字符串的开始结束处剪裁选定的字符。

259166 次浏览

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.

try:

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

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, "|") + "'" );

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

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 ifs 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\]\}"

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.

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);
};

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
}

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 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);
};

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');

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.

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.

function trim(text, val) {
return text.replace(new RegExp('^'+val+'+|'+val+'+$','g'), '');
}

Try this method:

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

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/

"|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.

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>

P.S.: 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.

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$%'));

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.

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');