Apara caractere específico de uma string


120

Qual é o JavaScript equivalente a este C#método:

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

C # apara o caractere selecionado apenas no início e no final da string!

Respostas:


155

Uma linha é suficiente:

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

Uma solução geral:

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

Se bem entendi, você deseja remover um caractere específico apenas se estiver no início ou no final da string (ex: ||fo||oo||||deve se tornar foo||oo). Você pode criar uma função ad hoc da seguinte maneira:

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

Testei essa função com o código abaixo:

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

3
Este seria um teste divertido para o coletor de lixo, mas eu não recomendaria submeter seus clientes a ele.
Sorensen de

18

Você pode usar uma expressão regular, como:

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

ATUALIZAR:

Se você deseja generalizar isso em uma função, você pode fazer o seguinte:

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

para manter esta questão atualizada:

aqui está uma abordagem que eu escolheria em vez da função regex usando o operador de propagação 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);
}

Versão melhorada após o comentário de @fabian (pode lidar com strings contendo apenas o mesmo caractere)

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
Eu sei que regexes são um exagero aqui, mas por que você escolheria essa implementação específica?
Nicholas Shanks,

2
esta implementação porque pessoalmente a considero bem legível. sem regex simplesmente porque a "árvore" de decisão nos motores de regex é muito maior. e especialmente porque os regexes usados ​​para corte contêm caracteres de consulta que levam ao retrocesso no mecanismo de regex. esses mecanismos frequentemente compilam o padrão em código de bytes, semelhante a instruções de máquina. o motor então executa o código, saltando de uma instrução para outra. quando uma instrução falha, ele então retorna para encontrar outra maneira de combinar a entrada. logo, muito mais acontecendo do que nec.
Robin F.

Obrigado por responder, embora eu queira que você explique por que você escolheu isso em vez de outras formas não regex de fazer isso - eu esperava mais do que apenas "Acho legível", suponho.
Nicholas Shanks

1
@RobinF. você acha que findIndex () e reverse () não contém loops? Pense de novo.
Andrew,

1
Duas anotações: Uma string contendo apenas o caractere a ser aparado não será aparada. O outro ponto é: explodir a string em uma matriz com o operador de propagação confundirá babel e a transformará em algo [].concat(string)que não seja o desejado. Usar Array.from(string)vai funcionar.
Fabian

14

Uma versão sem regex que é agradável à vista:

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

Para casos de uso em que temos certeza de que não há repetição dos caracteres nas bordas.


bastante interessante ... então a divisão retorna o elemento indefinido para igual a cada delimitador que é divididoconst 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

Se você estiver lidando com strings mais longas, acredito que isso deve superar a maioria das outras opções, reduzindo o número de strings alocadas para zero ou um:

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 se você quiser cortar um conjunto de vários caracteres:

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'

EDITAR: Para se divertir, corte palavras (em vez de caracteres individuais)

// 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
Prefiro essa solução porque ela é, de fato, eficiente, e não apenas curta.
tekHedd

Eu concordo que deveria ser preferido. Substitui uma resposta que eu dei.
TamusJRoyce

9

Isso pode cortar vários caracteres de uma vez:

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: Não, na verdade não. É uma demonstração, se você colar em um console, apenas imprimirá o resultado. Mas eu entendo que pode ser confuso, então eu editei.
marlar

2

Se você definir essas funções em seu programa, suas strings terão uma versão atualizada trimque pode cortar todos os caracteres fornecidos:

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)

Fonte

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


1

Que eu saiba, o jQuery não tem uma função incorporada ao método que você está perguntando. Com o javascript, no entanto, você pode apenas usar substituir para alterar o conteúdo da sua string:

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

Isso substituirá todas as ocorrências de | com nada.


existe uma maneira de remover | apenas no início / fim?
fubo,

Na verdade, acho que este post irá ajudá-lo a entender melhor sua pergunta: stackoverflow.com/questions/20196088/…
Ole Haugset

@fubo Claro ... Jogue $assim para apenas no final: "||spam|||".replace(/\|+$/g, "")ou ^assim para apenas no início:"||spam|||".replace(/^\|+/g, "")
ruffin de

1

Este corta todos os delimitadores anteriores e posteriores

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

Eu sugeriria olhar para Lodash e como eles implementaram a trimfunção.

Consulte Lodash Trim para a documentação e a fonte para ver o código exato que faz o corte.

Sei que isso não fornece uma resposta exata à sua pergunta, mas acho bom definir uma referência para uma biblioteca sobre essa questão, pois outros podem achar útil.


1
@TamusJRoyce não é o mesmo
gdbdable

@devi Eu só posso concordar. Obrigado pelo comentário. boa resposta procurando uma ferramenta com suporte da comunidade.
TamusJRoyce

1

A melhor maneira de resolver essa tarefa é (semelhante à trimfunção 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: por que postei minha resposta, quando a maioria das pessoas já fez isso antes? Porque eu encontrei "o melhor" erro em todas as respostas: todas usaram a meta '+' em vez de '*', porque trimdeve remover os caracteres SE ELES ESTÃO NO INÍCIO E / OU FIM, mas retorna a string original em caso contrário .


0

expandindo a resposta de @leaf, aqui está uma que pode ter vários caracteres:

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

Gosto da solução de @ Pho3niX83 ...

Vamos estendê-lo com "palavra" em vez 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);
};

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



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

Ele remove apenas uma ocorrência, mas não apara até que o caractere seja totalmente aparado
KoalaBear

1
Não substitua o protótipo de string padrão ou você terá problemas mais tarde. Crie suas próprias funções separadas em outro lugar.
rooby de

-2

Experimente este método:

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


1
Por quê? O que isso faz? Como funciona? Respostas apenas em código são consideradas de baixa qualidade no SO. Explique sua resposta para que o OP e quaisquer futuros visitantes possam aprender com ela.
Não entre em pânico,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.