Découper un caractère spécifique d'une chaîne


120

Quel est l' équivalent JavaScript de cette C#méthode:

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

C # coupe le caractère sélectionné uniquement au début et à la fin de la chaîne!

Réponses:


155

Une ligne suffit:

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

Une solution générale:

function trim (s, 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));
}


35

Si j'ai bien compris, vous souhaitez supprimer un caractère spécifique uniquement s'il se trouve au début ou à la fin de la chaîne (ex: ||fo||oo||||devrait devenir foo||oo). Vous pouvez créer une fonction ad hoc comme suit:

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

J'ai testé cette fonction avec le code ci-dessous:

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

3
Ce serait un test amusant pour le ramasse-miettes, mais je ne recommanderais pas d'y soumettre vos clients.
Sorensen

18

Vous pouvez utiliser une expression régulière telle que:

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

METTRE À JOUR:

Si vous souhaitez généraliser cela dans une fonction, vous pouvez effectuer les opérations suivantes:

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

17

pour garder cette question à jour:

voici une approche que je choisirais plutôt que la fonction regex en utilisant l'opérateur de propagation ES6.

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

Version améliorée après le commentaire de @fabian (peut gérer les chaînes contenant le même caractère uniquement)

function trimByChar(string, character) {
  const arr = Array.from(string);
  const first = arr.indexOf(character);
  const last = arr.reverse().indexOf(character);
  return string.substring(first + 1, string.length - last - 1);
}

2
Je sais que les regex sont exagérées ici, mais pourquoi choisiriez-vous cette implémentation particulière?
Nicholas Shanks

2
cette implémentation car personnellement je la trouve bien lisible. pas de regex simplement parce que "l'arbre" de décision dans les moteurs de regex est beaucoup plus grand. et en particulier parce que les expressions régulières utilisées pour le découpage contiennent des caractères de requête qui conduisent à un retour en arrière dans le moteur d'expression régulière. ces moteurs compilent souvent le modèle en code octet, ressemblant aux instructions de la machine. le moteur exécute alors le code, passant d'une instruction à l'autre. lorsqu'une instruction échoue, il effectue une recherche arrière pour trouver un autre moyen de faire correspondre l'entrée. ergo beaucoup plus que nécessaire.
Robin F.

Merci d'avoir répondu, même si je voulais que vous expliquiez pourquoi vous choisiriez cela plutôt que d'autres moyens non-regex de le faire - j'espérais plus que simplement "je le trouve lisible", je suppose.
Nicholas Shanks

1
@RobinF. vous pensez que findIndex () et reverse () ne contiennent pas de boucles? Pensez encore.
Andrew le

1
Deux annotations: Une chaîne contenant uniquement le caractère à découper ne sera pas du tout découpée. L'autre point est: l'explosion de la chaîne dans un tableau avec l'opérateur de propagation confondra babel et la transformera en [].concat(string)ce qui n'est pas le résultat souhaité. L'utilisation Array.from(string)fonctionnera.
Fabian le

14

Une version sans regex qui est agréable à l'œil:

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

Pour les cas d'utilisation où nous sommes certains qu'il n'y a pas de répétition des caractères sur les bords.


assez intéressant ... donc split renvoie un élément non défini pour égal à chaque délimiteur diviséconst trim = (str, chars) => str.split(chars).filter(x => { Boolean(x); console.log(typeof(x), x, Boolean(x)); }).join(chars); const str = "#//#//abc#//test#//end#//"; console.log(trim(str, '#//'));
TamusJRoyce

10

Si vous avez affaire à des chaînes plus longues, je pense que cela devrait surpasser la plupart des autres options en réduisant le nombre de chaînes allouées à zéro ou à un:

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'

Ou si vous souhaitez découper un ensemble de plusieurs caractères:

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'

MODIFIER: Pour le plaisir, découpez des mots (plutôt que des caractères individuels)

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

1
Je préfère cette solution car elle est, en fait, réellement efficace, plutôt que simplement courte.
tekHedd du

Je conviens que cela devrait être préféré. Remplace une réponse que j'avais donnée.
TamusJRoyce le

9

Cela peut couper plusieurs caractères à la fois:

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

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

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

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

@fubo: Non, pas vraiment. C'est une démo, si vous la collez dans une console, elle imprimera simplement le résultat. Mais je comprends que cela peut être déroutant, alors je l'ai modifié.
marlar

2

Si vous définissez ces fonctions dans votre programme, vos chaînes auront une version améliorée de trimqui peut couper tous les caractères donnés:

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)

La source

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


1

À ma connaissance, jQuery n'a pas de fonction intégrée à la méthode que vous demandez. Cependant, avec javascript, vous pouvez simplement utiliser replace pour modifier le contenu de votre chaîne:

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

Cela remplacera toutes les occurrences de | avec rien.


existe-t-il un moyen de supprimer | seulement au début / à la fin?
fubo

Je pense en fait que cet article vous permettra de répondre au mieux à votre question: stackoverflow.com/questions/20196088/…
Ole Haugset

@fubo Sure ... Jetez un $comme ça pour seulement à la fin: "||spam|||".replace(/\|+$/g, "")ou un ^comme ça pour seulement au début:"||spam|||".replace(/^\|+/g, "")
ruffin

1

Celui-ci coupe tous les délimiteurs de début et de fin

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

1

Je suggérerais de regarder lodash et comment ils ont mis en œuvre la trimfonction.

Voir Lodash Trim pour la documentation et la source pour voir le code exact qui effectue le rognage.

Je sais que cela ne fournit pas une réponse exacte à votre question, mais je pense qu'il est bon de définir une référence à une bibliothèque sur une telle question, car d'autres pourraient la trouver utile.


1
@TamusJRoyce pas le même
gdbdable

@devi Je ne peux qu'être d'accord. Merci pour le commentaire. bonne réponse à la recherche d'un outil soutenu par la communauté.
TamusJRoyce

1

La meilleure façon de résoudre cette tâche est (similaire avec la trimfonction PHP ):

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: pourquoi j'ai posté ma réponse, alors que la plupart des gens l'ont déjà fait avant? Parce que j'ai trouvé "la meilleure" erreur dans toutes leurs réponses: tous ont utilisé la méta '+' au lieu de '*', car ils trimdoivent supprimer les caractères SI ILS SONT EN DÉBUT ET / OU FIN, mais il renvoie la chaîne d'origine dans le cas contraire .


0

En développant la réponse de @leaf, en voici une qui peut prendre plusieurs caractères:

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
}

0

J'aime la solution de @ Pho3niX83 ...

Étendons-le avec "mot" au lieu de "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);
};




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

Il ne supprime qu'une occurrence, mais ne coupe pas tant que le personnage n'est pas entièrement coupé
KoalaBear

1
Ne remplacez pas le prototype de chaîne par défaut ou vous demandez des problèmes plus tard. Créez vos propres fonctions distinctes ailleurs.
rooby

-2

Essayez cette méthode:

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


1
Pourquoi? Qu'est-ce que cela fait? Comment ça marche? Les réponses basées uniquement sur le code sont considérées comme de faible qualité sur SO. Expliquez votre réponse afin qu'OP et les futurs visiteurs puissent en tirer des leçons.
Don't Panic
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.