JavaScript siekaj / wycinaj / przycinaj ostatni znak w ciągu


1973

Mam ciąg 12345.00i chciałbym, aby powrócił 12345.0.

Patrzyłem trim, ale wygląda na to, że to tylko przycinanie białych znaków, a slicenie wiem, jak to by działało. Jakieś sugestie?


36
Czy zależy ci na zaokrąglaniu? 12345.46 = 12345.5 lub 12345.4?
— RSolberg

9
Czy wiesz, co to jest przyrostek, czy chcesz podzielić i usunąć ostatnie słowo na podstawie podkreślenia?
— C

65
Ho ho ho, @RSolberg: nie można zaokrąglić sznurka!
— Ziggy,

50
@Ziggy mówi co? Math.round('0.5') === 1;)
— TWiStErRob

16
@TWiStErRob Oh JavaScript, co mam z tobą zrobić? * kręci głową *
— Chuck Le Butt,

Odpowiedzi:


3211

Możesz użyć funkcji podciągu :

let str = "12345.00";
str = str.substring(0, str.length - 1);
console.log(str);

To jest akceptowana odpowiedź, ale zgodnie z poniższymi rozmowami składnia plastra jest znacznie bardziej przejrzysta:

let str = "12345.00";
str = str.slice(0, -1); 
console.log(str);


23
@Kheu - notacja plastra jest dla mnie znacznie czystsza. Wcześniej korzystałem z wersji substring. Dzięki!
— Matt Ball

32
wybacz mi, jeśli się mylę, ale czy nie musisz ponownie przypisywać wartości str.substring do str? Jakstr = str.substring(0, str.length -1);
— Doug Molineux,

10
Wszystkie metody slice& substringsą takie same; z wyjątkiem tego, że slice()akceptuje indeks ujemny w stosunku do końca łańcucha, ale nie substring, powoduje out-of-boundbłąd
— Amol M Kulkarni

20
W przypadku, gdy ktoś się zastanawia, substringjest o 11% szybszy niż slice. jsperf.com/js-slice-vs-substring-test
— BenR

19
substring to szalone mikrooptymalizacje, których nie sądzę, że powinieneś robić. Najpierw zmaksymalizuj dla czytelności. W razie potrzeby zoptymalizuj nisko wiszące owoce.
— Alfred

1306

Możesz użyć plasterka ! Musisz tylko upewnić się, że wiesz, jak go używać. Dodatnie liczby # odnoszą się do początku, liczby ujemne odnoszą się do końca.

js>"12345.00".slice(0,-1)
12345.0

75
W porównaniu do przyjętego rozwiązania jest to o wiele bardziej eleganckie i może być używane nawet z dynamicznie tworzonymi łańcuchami
— Sameer Alibhai

1
Lubię to, ponieważ bawi się myśleniem php o funkcji substr, łatwiej zapamiętuje i pisze w locie.
— pathfinder

2
@SameerAlibhai Zgadzam się z tobą, ale czy nie substringmożna zastosować tej metody również w przypadku ciągów dynamicznych? Korzystając z str. Length, aby dynamicznie uzyskać długość?
— Doug Molineux,

Należy dodać, że pierwszy indeks jest włączający, a drugi wyłączny.
— Miscreant,

@KevinBeal możesz po prostu użyć F12 w głównych przeglądarkach i wprowadzić go w konsoli, działa na dowolnej stronie, a nawet masz kontekst i możesz mieć załadowane biblioteki.
— TWiStErRob

263

Możesz użyć metody podciągów obiektów łańcuchowych JavaScript:

s = s.substring(0, s.length - 4)

Bezwarunkowo usuwa ostatnie cztery znaki z łańcucha s.

Jeśli jednak chcesz warunkowo usunąć ostatnie cztery znaki, tylko jeśli są one dokładnie _bar :

var re = /_bar$/;
s.replace(re, "");

107
slicetu jest lepiej. s.slice(0, -4)
— Tim Down

12
Alternatywnie: s.slice (0, - „_ bar” .length) (przydatne, jeśli nie chce się na stałe kodować liczby znaków)
— Mahn

3
Podoba mi się ten, ponieważ pomaga również w zastąpieniu określonego zakończenia.
— Mike Graf

162

Najłatwiejszą metodą jest użycie slicemetody ciągu, która pozwala na pozycje ujemne (odpowiadające przesunięciom z końca łańcucha):

const s = "your string";
const withoutLastFourChars = s.slice(0, -4);

Jeśli potrzebujesz czegoś bardziej ogólnego, aby usunąć wszystko po ostatnim podkreśleniu (włącznie z nim), możesz wykonać następujące czynności (pod warunkiem, sże zawiera on co najmniej jeden znak podkreślenia):

const s = "your_string";
const withoutLastChunk = s.slice(0, s.lastIndexOf("_"));
console.log(withoutLastChunk);


67

W przypadku liczby takiej jak twój przykład zaleciłbym zrobienie tego ponad substring:

console.log(parseFloat('12345.00').toFixed(1));

Zauważ, że to faktycznie zaokrągli liczbę, co, jak sądzę, jest pożądane, ale może nie:

console.log(parseFloat('12345.46').toFixed(1));


11
+1 Tego potrzebuje OP, zapomnij o fałszywym założeniu, że istnieją ciągi do przycięcia.
— naugtur,

2
To nie jest fałszywe założenie, OP mówi o ciągach znaków. Twoje jest fałszywym założeniem, ponieważ OP nie mówi o zaokrąglaniu liczb.
— Fernando

30

Korzystanie z funkcji wycinka JavaScript:

let string = 'foo_bar';
string = string.slice(0, -4); // Slice off last four characters here
console.log(string);

Można tego użyć do usunięcia „_bar” na końcu łańcucha dowolnej długości.


19

Wyrażenie regularne jest tym, czego szukasz:

let str = "foo_bar";
console.log(str.replace(/_bar$/, ""));


Twoje rozwiązanie działa, ale odpowiedź Alexa jest bardziej wyczerpująca. Więc zaakceptuję jego. Dzięki!
— Albert

1
To rozwiązuje związany z tym problem warunkowego usuwania zamiast ślepego obcinania
— Aaron



9

Użyj wyrażenia regularnego:

let aStr = "12345.00";
aStr = aStr.replace(/.$/, '');
console.log(aStr);


Poza tym, że nie obsługuje Unicode, to również nie pasuje do podziałów linii.
— user4642212

7
  1. (. *), przechwytuje dowolną postać wiele razy

console.log("a string".match(/(.*).$/)[1]);

  1. ., w tym przypadku dopasowuje ostatni znak

console.log("a string".match(/(.*).$/));

  1. $, dopasowuje koniec łańcucha

console.log("a string".match(/(.*).{2}$/)[1]);


9
Podoba mi się, ponieważ pomimo .splice () znalazłeś sposób na użycie wyrażenia regularnego.
— QueueHammer

Poza tym, że nie obsługuje Unicode, to również nie pasuje do podziałów linii.
— user4642212


5

Oto alternatywa, której nie widziałem w innych odpowiedziach, dla zabawy.

var strArr = "hello i'm a string".split("");
strArr.pop();
document.write(strArr.join(""));

Nie jest tak czytelny ani prosty jak plasterek lub podciąg, ale pozwala grać z ciągiem przy użyciu kilku fajnych metod tablicowych, więc warto wiedzieć.


4
debris = string.split("_") //explode string into array of strings indexed by "_"

debris.pop(); //pop last element off the array (which you didn't want)

result = debris.join("_"); //fuse the remainng items together like the sun


3

Jeśli chcesz zrobić ogólne zaokrąglanie liczb zmiennoprzecinkowych, zamiast przycinać ostatni znak:

var float1 = 12345.00,
    float2 = 12345.4567,
    float3 = 12345.982;

var MoreMath = {
    /**
     * Rounds a value to the specified number of decimals
     * @param float value The value to be rounded
     * @param int nrDecimals The number of decimals to round value to
     * @return float value rounded to nrDecimals decimals
     */
    round: function (value, nrDecimals) {
        var x = nrDecimals > 0 ? 10 * parseInt(nrDecimals, 10) : 1;
        return Math.round(value * x) / x;
    }
}

MoreMath.round(float1, 1) => 12345.0
MoreMath.round(float2, 1) => 12345.5
MoreMath.round(float3, 1) => 12346.0

EDYCJA: Wydaje się, że istnieje wbudowana funkcja do tego, jak zauważa Paolo. To rozwiązanie jest oczywiście znacznie czystsze niż moje. Użyj parseFloat, a następnie toFixed




1

Wydajność

Dzisiaj 2020.05.13 przeprowadzam testy wybranych rozwiązań na Chrome v81.0, Safari v13.1 i Firefox v76.0 na MacOs High Sierra 10.13.6.

Wnioski

  • slice(0,-1)(D) jest szybki i najszybszym rozwiązaniem dla krótkich i długich ciągów i zaleca się jako szybkie rozwiązanie cross-browser
  • rozwiązania oparte na substring(C) i substr(E) są szybkie
  • rozwiązania oparte na wyrażeniach regularnych (A, B) są wolne / średnio szybkie
  • rozwiązania B, F i G są wolne dla długich łańcuchów
  • rozwiązanie F jest najwolniejsze dla krótkich łańcuchów, G jest najwolniejsze dla długich łańcuchów

wprowadź opis zdjęcia tutaj

Detale

Przeprowadzam dwa testy dla rozwiązań A , B , C , D , E ( ext ), F , G (mój)

  • dla 8-znakowego krótkiego ciągu (od pytania OP) - możesz go uruchomić TUTAJ
  • na łańcuch 1M - możesz go uruchomić TUTAJ

Rozwiązania są przedstawione poniżej

Oto przykładowe wyniki dla Chrome dla krótkiego ciągu

wprowadź opis zdjęcia tutaj


1

Pamiętaj, że String.prototype.{ split, slice, substr, substring }działają na ciągach kodowanych w UTF-16

Żadna z poprzednich odpowiedzi nie obsługuje Unicode. Łańcuchy są kodowane jako UTF-16 w większości nowoczesnych silników JavaScript, ale wyższe punkty kodu Unicode wymagają par zastępczych , więc starsze, wcześniej istniejące metody łańcuchów działają na jednostkach kodu UTF-16, a nie punktach kodu Unicode.

const string = "ẞ🦊";

console.log(string.slice(0, -1)); // "ẞ\ud83e"
console.log(string.substr(0, string.length - 1)); // "ẞ\ud83e"
console.log(string.substring(0, string.length - 1)); // "ẞ\ud83e"
console.log(string.replace(/.$/, "")); // "ẞ\ud83e"
console.log(string.match(/(.*).$/)[1]); // "ẞ\ud83e"

const utf16Chars = string.split("");

utf16Chars.pop();
console.log(utf16Chars.join("")); // "ẞ\ud83e"

Ponadto odpowiedzi RegExp nie pasują do podziałów linii na końcu w ich obecnej formie:

const string = "Hello, world!\n";

console.log(string.replace(/.$/, "").endsWith("\n")); // true
console.log(string.match(/(.*).$/) === null); // true


Użyj iteratora ciągów do iteracji znaków

Kod obsługujący Unicode wykorzystuje iterator łańcucha; widzieć Array.fromi ...rozprzestrzeniać się . string[Symbol.iterator]można użyć (np. zamiaststring ).

Zobacz także Jak podzielić ciąg znaków Unicode na znaki w JavaScript .

Przykłady:

const string = "ẞ🦊";

console.log(Array.from(string).slice(0, -1).join("")); // "ẞ"
console.log([
  ...string
].slice(0, -1).join("")); // "ẞ"

Użyj flag si unaRegExp

Te dotAlllub sflag marki .dopasować znaki przerwy linii, unicodeczy uflaga umożliwia pewne funkcje związane z Unicode.

Przykłady:

const unicodeString = "ẞ🦊",
  lineBreakString = "Hello, world!\n";

console.log(lineBreakString.replace(/.$/s, "").endsWith("\n")); // false
console.log(lineBreakString.match(/(.*).$/s) === null); // false
console.log(unicodeString.replace(/.$/su, "")); // ẞ
console.log(unicodeString.match(/(.*).$/su)[1]); // ẞ

// Now `split` can be made Unicode-aware:

const unicodeCharacterArray = unicodeString.split(/(?:)/su),
  lineBreakCharacterArray = lineBreakString.split(/(?:)/su);

unicodeCharacterArray.pop();
lineBreakCharacterArray.pop();
console.log(unicodeCharacterArray.join("")); // "ẞ"
console.log(lineBreakCharacterArray.join("").endsWith("\n")); // false


Zauważ, że niektóre grafemy składają się z więcej niż jednego punktu kodowego, np. 🏳️‍🌈Który składa się z sekwencji 🏳(U + 1F3F3), VS16(U + FE0F) , ZWJ(U + 200D) , 🌈(U + 1F308). Tutaj nawet Array.frompodzieli to na cztery „postacie”. Dopasowanie ich jest możliwe dzięki właściwości Unicode, która ucieka od propozycji właściwości sekwencji .


-1

W przypadkach, gdy chcesz usunąć coś, co znajduje się blisko końca łańcucha (w przypadku łańcuchów o zmiennej wielkości), możesz połączyć slice () i substr ().

Miałem ciąg znaków ze znacznikami, zbudowany dynamicznie, z listą tagów kotwicy oddzielonych przecinkiem. Ciąg był podobny do:

var str = "<a>text 1,</a><a>text 2,</a><a>text 2.3,</a><a>text abc,</a>";

Aby usunąć ostatni przecinek, wykonałem następujące czynności:

str = str.slice(0, -5) + str.substr(-4);

-3

Spróbuj tego:

<script>
    var x="foo_foo_foo_bar";
    for (var i=0; i<=x.length; i++) {
        if (x[i]=="_" && x[i+1]=="b") {
            break;
        }
        else {
            document.write(x[i]);
        }
    }
</script>

Możesz także wypróbować działający przykład na żywo pod adresem http://jsfiddle.net/informativejavascript/F7WTn/87/ .


3
Dzięki kamal. Jednak zaznaczyłem powyższą odpowiedź jako zaakceptowaną dla moich potrzeb. Zwróć uwagę na zielony znacznik wyboru powyżej. Chociaż sprawdziłem twój kod. :) Teraz, w mojej sytuacji, znam tylko wspólną sekwencję znaków końcowych. Lepiej po prostu zacząć sprawdzanie od końca łańcucha. Twoja sugestia nie powiedzie się, jeśli mam ciąg znaków, który wygląda jak „foo_b_bar”, i chcę tylko usunąć ostatni „_bar”. W każdym razie dzięki! Zadawanie pytań ponad 2 lata temu jest dość interesującym doświadczeniem i nadal otrzymuję odpowiedzi na nie dzisiaj. :)
— Albert

-4

@Jason S:

Możesz użyć plasterka! Musisz tylko upewnić się, że wiesz, jak go używać. Dodatnie liczby # odnoszą się do początku, liczby ujemne odnoszą się do końca.

js> „12345.00” .slice (0, -1) 12345.0

Przepraszam za moje grafiki, ale post został wcześniej oznaczony jako „jquery”. Tak więc nie możesz używać slice () wewnątrz jQuery, ponieważ slice () jest metodą jQuery do operacji z elementami DOM, a nie podciągami ... Innymi słowy odpowiedź @Jon Erickson sugeruje naprawdę idealne rozwiązanie.

Jednak twoja metoda będzie działała poza funkcją jQuery, w prostym JavaScript. Muszę powiedzieć ze względu na ostatnią dyskusję w komentarzach, że jQuery jest znacznie częściej odnawialnym rozszerzeniem JS niż jego najbardziej znany ECMAScript.

Istnieją również dwie metody:

jak nasz:

string.substring(from,to) plus plus, jeśli indeks „do” nulled zwraca resztę ciągu. więc: string.substring(from) pozytywne lub negatywne ...

i niektóre inne - substr () - które zapewniają zakres podciągów i „długość” mogą być dodatnie: string.substr(start,length)

Również niektórzy opiekunowie sugerują, że ostatnia metoda string.substr(start,length)nie działa lub działa z błędem dla MSIE.


3
Co masz na myśli? String.prototype.slicejest rodzimą metodą
— naugtur,

to tylko to, co powiedziałeś. Metoda rodzima Javascript, ale także slice()metoda jQuery do manipulacji DOM: jQuery API: .slice () . I PEWNE, że MOŻNA ZROBIĆ jak polimorficzne dziedziczenie JS Array.slice (), ale są to dwie różne metody i myślę, że należy je rozróżnić. Jest to więc tylko przybliżenie tej wiedzy.
— szybki

12
Jeśli wywołasz .slicezmienną, która jest łańcuchem, zrobi to, co chciał OP. Nie ma znaczenia, czy jest to „wewnątrz jQuery” i nie ma żadnego sposobu, by „ingerował” w jakikolwiek sposób, chyba że nadpiszesz String.prototypejQuery, co, jestem pewien, uniemożliwi działanie KAŻDEGO kodu javascript. Twoja odpowiedź mówi tylko, że inna odpowiedź nie jest dobra, a argument, który podałeś, jest nieprawidłowy.
— naugtur,

1
Mogę się zgodzić z @naugtur, że ta odpowiedź jest błędna, jQuery nie stosuje metody wycinania łańcucha.
— Rebbot

1
Myślę, że celem naugtur było po prostu to, że możliwe, że możesz skończyć z łańcuchem owiniętym przez obiekt jQuery (np. Jeśli wykonasz jakieś wymyślne .datamanipulacje i skończysz z tym „łańcuchem”), który jeśli slicego wywołałeś , nie zrobiłby tego, co chcesz. To powiedziawszy, to nie jest naprawdę pomocna odpowiedź.
— mAAdhaTTah

-8

Użyj podciągów, aby uzyskać wszystko po lewej stronie _bar. Ale najpierw musisz pobrać instrukcję _bar w ciągu:

str.substring(3, 7);

3 to ten początek, a 7 to długość.


1
działa to tylko na „foo_bar”, a nie na „foo_foo_bar”, pytanie dotyczyło ciągu o dowolnej długości, ale o znanym końcu.
— Projekt Adrian
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.