Wytnij określony znak z ciągu

120

Jaki jest odpowiednik tej metody w JavaScriptC# :

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

C # przycina wybrany znak tylko na początku i na końcu ciągu!

fubo
źródło

Odpowiedzi:

155

Wystarczy jedna linia:

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

Ogólne rozwiązanie:

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

liść
źródło
35

Jeśli dobrze zrozumiałem, chcesz usunąć określony znak tylko wtedy, gdy znajduje się na początku lub na końcu ciągu (np. ||fo||oo||||Powinien stać się foo||oo). Funkcję ad hoc można utworzyć w następujący sposób:

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

Przetestowałem tę funkcję za pomocą poniższego kodu:

var str = "|f|oo||";
$( "#original" ).html( "Original String: '" + str + "'" );
$( "#trimmed" ).html( "Trimmed: '" + trimChar(str, "|") + "'" );
Pho3niX83
źródło
3
To byłby fajny test dla odśmiecacza, ale nie polecałbym poddawać mu swoich klientów.
Sorensen
18

Możesz użyć wyrażenia regularnego, takiego jak:

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

AKTUALIZACJA:

Jeśli chcesz uogólnić to na funkcję, możesz wykonać następujące czynności:

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
neelsg
źródło
17

aby to pytanie było aktualne:

tutaj jest podejście, które wybrałbym zamiast funkcji regex przy użyciu operatora spreadu 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);
}

Ulepszona wersja po komentarzu @fabian (obsługuje ciągi zawierające tylko ten sam znak)

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);
}
Robin F.
źródło
2
Wiem, że wyrażenia regularne są tutaj przesadą, ale dlaczego miałbyś wybrać tę konkretną implementację?
Nicholas Shanks
2
ta implementacja, ponieważ osobiście uważam ją za dobrze czytelną. brak wyrażenia regularnego po prostu dlatego, że „drzewo” decyzyjne w silnikach wyrażeń regularnych jest znacznie większe. a zwłaszcza dlatego, że wyrażenia regularne używane do przycinania zawierają znaki zapytania, które prowadzą do cofania się w silniku wyrażeń regularnych. takie silniki często kompilują wzorzec w kod bajtowy, przypominający instrukcje maszynowe. silnik następnie wykonuje kod, przeskakując od instrukcji do instrukcji. gdy instrukcja się nie powiedzie, cofa się, aby znaleźć inny sposób dopasowania danych wejściowych. ergo dzieje się dużo więcej niż gdzie indziej.
Robin F.,
Dziękuję za odpowiedź, chociaż chciałem, żebyś wytłumaczył, dlaczego wybrałeś ten sposób, a nie inne sposoby robienia tego, które nie są regexowe - miałem nadzieję na coś więcej niż tylko „uważam to za czytelne”, jak sądzę.
Nicholas Shanks
1
@RobinF. myślisz, że findIndex () i reverse () nie zawierają pętli? Pomyśl jeszcze raz.
Andrew,
1
Dwie adnotacje: Ciąg zawierający tylko znak do przycięcia nie zostanie w ogóle przycięty. Drugi punkt jest taki: rozbicie łańcucha na tablicę za pomocą operatora spreadu zmyli babel i przekształci go w [].concat(string)nie pożądany wynik. Używanie Array.from(string)będzie działać.
Fabian
14

Wersja bez wyrażeń regularnych, która jest przyjemna dla oka:

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

Do przypadków użycia, w których jesteśmy pewni, że nie ma powtórzeń znaków poza krawędziami.

mbaer3000
źródło
całkiem interesujące ... więc split zwraca niezdefiniowany element za równy każdemu rozdzielającemu separatorowiconst 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

Jeśli masz do czynienia z dłuższymi ciągami, uważam, że powinno to przewyższyć większość innych opcji, zmniejszając liczbę przydzielonych ciągów do zera lub jednego:

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'

Lub jeśli chcesz wyciąć z zestawu wielu znaków:

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'

EDYCJA: Dla zabawy, przycinaj słowa (zamiast pojedynczych znaków)

// 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');
Jason Larke
źródło
1
Wolę to rozwiązanie, ponieważ jest faktycznie wydajne, a nie tylko krótkie.
tekHedd
Zgadzam się, że powinno to być preferowane. Zastępuje odpowiedź, której udzieliłem.
TamusJRoyce
9

Może to przyciąć kilka znaków naraz:

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
marlar
źródło
@fubo: Nie, nie bardzo. To wersja demonstracyjna, jeśli wkleisz ją w konsoli, po prostu wydrukuje wynik. Ale rozumiem, że może to być mylące, więc zredagowałem to.
marlar
2

Jeśli zdefiniujesz te funkcje w swoim programie, twoje ciągi będą miały ulepszoną wersję, trimktóra może przyciąć wszystkie podane znaki:

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)

Źródło

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

Chris Redford
źródło
1

O ile mi wiadomo, jQuery nie ma wbudowanej funkcji, o którą pytasz. Jednak w javascript możesz po prostu użyć zamiany, aby zmienić zawartość swojego ciągu:

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

Spowoduje to zastąpienie wszystkich wystąpień | z niczym.

Ole Haugset
źródło
czy istnieje sposób na usunięcie | tylko na początku / końcu?
fubo
Właściwie myślę, że ten post pozwoli Ci najszybciej odpowiedzieć na Twoje pytanie: stackoverflow.com/questions/20196088/…
Ole Haugset
@fubo Jasne ... Wrzuć coś $takiego tylko na koniec: "||spam|||".replace(/\|+$/g, "")lub coś ^takiego tylko na początku:"||spam|||".replace(/^\|+/g, "")
ruffin
1

Ten przycina wszystkie ograniczniki wiodące i końcowe

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
Dmitriy Botov
źródło
1

Sugerowałbym przyjrzenie się lodashowi i temu, jak realizowali tę trimfunkcję.

Zobacz Lodash Trim, aby uzyskać dokumentację i źródło, aby zobaczyć dokładny kod, który wykonuje przycinanie.

Wiem, że to nie daje dokładnej odpowiedzi na twoje pytanie, ale myślę, że dobrze jest ustawić odniesienie do biblioteki na takie pytanie, ponieważ inni mogą uznać to za przydatne.

drew7721
źródło
1
@TamusJRoyce to nie to samo
gdbdable
@devi Mogę się tylko zgodzić. dziękuje za komentarz. dobra odpowiedź, patrząc na narzędzie obsługiwane przez społeczność.
TamusJRoyce
1

Najlepszym sposobem rozwiązania tego zadania jest (podobnie jak w przypadku trimfunkcji 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: dlaczego opublikowałem swoją odpowiedź, skoro większość ludzi już to zrobiła? Ponieważ znalazłem „najlepszy” błąd we wszystkich odpowiedziach: wszyscy używali meta „+” zamiast „*”, ponieważ „ trimmuszą usunąć znaki, JEŚLI SĄ NA POCZĄTKU I / LUB KOŃCU, ale zwracają oryginalny ciąg w innym przypadku .

StoneCountry
źródło
0

rozwijając odpowiedź @leaf, oto taka, która może mieć wiele znaków:

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
}
AmitK
źródło
0

Podoba mi się rozwiązanie z @ Pho3niX83 ...

Rozszerzmy go o „słowo” zamiast „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);
};
foxontherock
źródło
0
function trim(text, val) {
    return text.replace(new RegExp('^'+val+'+|'+val+'+$','g'), '');
}
Alexander Ladonin
źródło
0
"|Howdy".replace(new RegExp("^\\|"),"");

(zwróć uwagę na podwójny znak ucieczki. \\potrzebny, aby mieć faktycznie pojedynczy ukośnik w ciągu , co następnie prowadzi do zmiany znaczenia |w regExp ).

Tylko kilka znaków wymaga regExp-Escaping. , wśród nich operator potoku.

Frank Nocke
źródło
-1

próbować:

console.log(x.replace(/\|/g,''));
Programista
źródło
-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);
};
Tobo
źródło
Usuwa
1
Nie nadpisuj domyślnego prototypu łańcucha lub poprosisz o późniejsze problemy. Utwórz własne oddzielne funkcje w innym miejscu.
rooby
-2

Wypróbuj tę metodę:

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

Ali CAKIL
źródło
1
Czemu? Co to robi? Jak to działa? Odpowiedzi zawierające tylko kod są uważane za niską jakość w SO. Wyjaśnij swoją odpowiedź, aby OP i przyszli goście mogli się z niej uczyć.
Don't Panic