Pytanie Regex, aby zachować 4 ostatnie znaki ciągu nieznanej długości za pomocą C #


Muszę użyć wyrażenia regularnego, aby zachować 4 ostatnie znaki ciągu. Nie znam długości struny, więc muszę zacząć od końca i liczyć do tyłu. Program napisany jest w języku c #.

Poniżej znajdują się dwa przykładowe ciągi:

  • 840057
  • 1002945

Potrzebuję wyniku (ostatnie 4 znaki):

  • 0057
  • 2945

Mój oryginalny wiersz kodu używał Regex.Replace, ale nie mogłem znaleźć regexu do pracy, jak widać w komentarzach poniżej.

replacementVal = Regex.Replace(replacementVal, wildcard.Regex, wildcard.RegexReplaceBy);

Zmieniłem kod na Regex.Match, a następnie wyrażenie regularne (?s)[0-9]{4}$ działało idealnie (patrz poniżej):

replacementVal = Regex.Replace(replacementVal, wildcard.Regex, wildcard.RegexReplaceBy);

Jednak użycie Regex.Match powoduje złamanie innych wyrażeń regularnych, których używam, na przykład używam ^(.).* aby odzyskać pierwszą literę imienia. Działa to przy użyciu Regex.Replace, ale nie działa przy użyciu Regex.Match.

Mój kod znajduje się poniżej, zauważ oryginalny wiersz zawierający Regex.Replace jest zakomentowany.

Dlaczego Regex.Match działa z jednym wyrażeniem, a Regex.Replace z innym?

      /// Replaces a wildcard in a string
        /// </summary>
        /// <param name="str">The string for which to replace the wildcards</param>
        /// <param name="row">The DataRow in which the string exists</param>
        /// <param name="wildcard">The wildcard to replace</param>
        /// <returns>The string with the wildcard replaced</returns>
        private static string ReplaceWildcardInString(string str, DataRow row, Wildcard wildcard)
        {
            // If the string is null or empty, return it as is
            if (string.IsNullOrEmpty(str))
                return str;

            // This will hold the replacement value
            var replacementVal = string.Empty;

            // If the replacement column value is not empty
            if (!row.IsDBNullOrNull(wildcard.ReplaceByColumnName))
            {
                // Convert its value to string
                replacementVal = row[wildcard.ReplaceByColumnName].ToString();

                // Apply wildcard regex if given
                if (!string.IsNullOrEmpty(wildcard.Regex) && wildcard.RegexReplaceBy != null)
                    //replacementVal = Regex.Replace(replacementVal, wildcard.Regex, wildcard.RegexReplaceBy);
                    replacementVal = Regex.Match(replacementVal, wildcard.Regex).Value;
            }

            // Replace all wildcards with the replacement value (case insensitive)
            var wildcardPattern = Regex.Escape(string.Format("%{0}%", wildcard.Name));
            str = Regex.Replace(str, wildcardPattern, replacementVal, RegexOptions.Singleline | RegexOptions.IgnoreCase);

            // Return the new string
            return str;
        }

Wielkie dzięki, doceniam pomoc.


14
2018-06-29 12:38


pochodzenie


a jeśli ciąg nie ma 4 znaki długie? - Gordon
to działałoby /....$/ - Harpreet Singh
Ciąg ma co najmniej 6 znaków, przepraszam, powinienem był to powiedzieć. - user1226884
Czy mógłbyś nieco wyjaśnić swoje pytanie? Ty masz replacementVal = Regex.Replace(replacementVal, wildcard.Regex, wildcard.RegexReplaceBy); dwa razy i po skomentowaniu linii. O co ci chodzi? Czy to też działa? Regex.Replace skomentował i Regex.Match Prace? Jeśli tak, czy chcesz go użyć Regex.Replace zamiast Regex.Match? - ivcubr
Jasne, spróbuję wyjaśnić to pytanie. Oryginalny kod używał Regex.Replace, co oznaczało, że wyrażenie regularne ^ (.). * Działało, aby pobrać pierwszą literę ciągu, ale nie mogłem uzyskać żadnego regexu do pracy, które pozostawiło mnie czterema ostatnimi cyframi ciągu znaków, było tak długo, aż zmieniłem na Regex.Match, który wtedy pozwolił (? s) [0-9] {4} $ na pracę. - user1226884


Odpowiedzi:


The Regex.Replace metoda zastępuje wszystkie niepokrywające się ciągi, które pasują do wzorca wyrażeń regularnych z określonym zamiennikiem.

The Regex.Match metoda przeszukuje podany ciąg wejściowy dla pierwszego wystąpienia wyrażenia regularnego.

Tak więc, gdy masz ciąg jak 1002945, a chcesz uzyskać dokładnie 4 cyfry od końca, możesz użyć

var result = Regex.Replace("1002945", @".*([0-9]{4})$", "$1", RegexOptions.Singleline);

lub

var matchResult = Regex.Match("1002945", @"[0-9]{4}$");
if (matchResult.Success) 
{
    Console.WriteLine(matchResult.Value);
}

Po zamianie musisz dopasować cały ciąg, dopasuj i zdobyć tylko ostatnie cztery znaki będące cyframi i potwierdzające indeks regex znajdują się na końcu ciągu znaków ($). Zwróć uwagę na użycie RegexOptions.Singleline opcja pozwala . aby dopasować znak nowej linii, który domyślnie nie pasuje. Ciąg zastępujący powinien być $1, zastępczą referencję wsteczną do pierwszej grupy przechwytywania, która przechwytuje cyfry.

Kiedy używasz Regex.Match("1002945", @"[0-9]{4}$").Value, ty mecz 4 cyfry, które są następnie zakończone ciągiem znaków lub znakiem nowej linii i końcem łańcucha znaków (ponieważ $ mecze takie, jeśli nie chcesz dopuścić do dopasowania przed znakiem nowej linii i końca łańcucha, użyj \z manchor). Po uzyskaniu wyniku możesz sprawdzić, czy to był sukces czy porażka matchResult.Success, a jeśli był mecz, zdobądź matchResult.Value. Już nie potrzebujesz RegexOptions.Singleline ponieważ nie ma . w wyrażeniu regularnym.


12
2017-07-07 12:12



Dziękuję za to wyjaśnienie. Wszystko teraz działa dobrze. Dzięki - user1226884


.*(?=.{4})$

dopasuje wszystko do czterech ostatnich znaków ciągu. Jeśli zastąpisz to dopasowanie przez String.Empty, pozostają tylko te cztery postacie.

Jeśli ciąg zawiera mniej niż cztery znaki, pozostaną one w ciągu znaków, ponieważ wyrażenie regularne nie będzie w ogóle pasowało, więc nic nie zostanie zastąpione.


7
2018-06-29 12:47



Być może brakuje mi czegoś, ale kiedy go używam. {4} $ Zostało mi 100 ze 1002945, a nie 4 ostatnie cyfry. - user1226884
Tak nie powinno być. Jak nazywasz przechwytywanie wyrażenia regularnego? - Cid
Nawiasem mówiąc, jego odpowiedź jest z pewnością najlepsza - Cid
Twoje pytanie było niejasne - wszyscy interpretowaliśmy to jako "chcę dopasować ostatnie cztery znaki ciągu". Chcesz dopasować wszystko oprócz czterech ostatnich znaków i zastąpić je pustym łańcuchem. Podaj szczegółowe pytanie podczas pisania pytania :) - Tim Pietzcker
@ user1226884 Tak właśnie mówił Tim. .*(?=.{4})$ przechwytuje 100 w 1002945. Następnie po zastąpieniu go "" pozostaje ci 2945. - emsimpson92


W tym celu nie trzeba używać wyrażenia regularnego.

string MyLast4Characters = MyString.Substring(((MyString.Length >= 4) ? (MyString.Length - 4) : (0)));

Ta część ((MyString.Length >= 4) ? (4) : (0)) służy do sprawdzenia, czy oryginalny ciąg jest dłuższy lub równy 4 znakom, a następnie zwróci 4 ostatnie znaki, w przeciwnym razie cały ciąg


3
2018-06-29 12:42



W tej sytuacji potrzebuję używać regex, niestety. Doceniam jednak fragment kodu. - user1226884


Jeśli to musi być wyrażenie regularne, myślę, że chcesz: .{4}(?=\s|$)

Ale zgadzam się, że regex prawdopodobnie nie jest najlepszym rozwiązaniem.

Załamanie:

. : any character {4} : exacty four times (?= : followed by \s : white space | : or $ : a line ending ) : end the followed by section


1
2018-06-29 12:52



Kiedy używam. {4} (? = \ S | $) Zostało mi 100 z 1002945, a nie 4 ostatnie cyfry, może coś jest nie tak z moim wdrożeniem. - user1226884
Jeśli spojrzysz tutaj: regex101.com/r/IDMkzM/5 wygląda na to, że to działa poprawnie. Jeśli używasz Regex.Replace prawdopodobnie zostaniesz z "100", ponieważ to zastąpiony dopasowana część (2945) @ użytkownik1226884 - Jacob Boertjes


Sądzę, że to jest coś z twoim RegexOptions. W moim przykładzie używam SingleLine tryb ((?s)) i ciąg wielowierszowy:

static void RegexTest()
{
    string str = "i am long string\r\nwith the number 1002945";
    string pattern = @"(?s)[0-9]{4}$"; // or @"(?s).{4}$"
    string num = Regex.Match(str, pattern).Value;
}

0
2018-06-30 07:50



Wewnątrz (?s)[0-9]{4}$, (?s) jest zbędny. Wzór nie ma kropki. Zobacz moją odpowiedź, gdzie wyjaśnię nieco, co RegexOptions.Singleline (lub jego wbudowany (?s) wersja) ma. - Wiktor Stribiżew


Chciałbym użyć Regex.Match metoda.
Dopasowuje tylko to, czego potrzebujesz.

Możesz go użyć na dwa sposoby.

string str = "asdf 12345";
if (str.Length > 4)
{
    // Abbreviated ..
    Console.WriteLine( "{0}", Regex.Match(str, @"(?s).{5}$").Value );

    // Verbose ...
    Regex rx = new Regex(@"(?s).{5}$");
    str = rx.Match(str).Value;
    Console.WriteLine( "{0}", str );
}
else {} // Do something else

Wydajność

12345
12345

0
2017-07-08 21:31





możesz spróbować i użyć Reverse() w tym celu

Na przykład:-

string input = "1002945";
string rev = new string(input.Reverse().ToArray());
string res = null;

Match match = Regex.Match(rev, @"\d{4}");
if (match != null && !String.IsNullOrEmpty(match.Value))
{
   res = new string(match.Value.Reverse().ToArray());
}

wydajność:-

2945

Dot.fiddle sample


0
2017-07-09 12:14