รับ Substring - ทุกอย่างก่อนอักขระบางตัว


124

ฉันกำลังพยายามหาวิธีที่ดีที่สุดในการรับทุกอย่างก่อนอักขระ - ในสตริง สตริงตัวอย่างบางส่วนอยู่ด้านล่าง ความยาวของสตริงก่อน - แตกต่างกันไปและอาจมีความยาวเท่าใดก็ได้

223232-1.jpg
443-2.jpg
34443553-5.jpg

ดังนั้นฉันต้องการค่าที่มาจากดัชนีเริ่มต้นเป็น 0 ถึงก่อนหน้า - ดังนั้นสตริงย่อยจะกลายเป็น 223232, 443 และ 34443553

คำตอบ:


144

ตัวอย่าง. Net Fiddle

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("223232-1.jpg".GetUntilOrEmpty());
        Console.WriteLine("443-2.jpg".GetUntilOrEmpty());
        Console.WriteLine("34443553-5.jpg".GetUntilOrEmpty());

        Console.ReadKey();
    }
}

static class Helper
{
    public static string GetUntilOrEmpty(this string text, string stopAt = "-")
    {
        if (!String.IsNullOrWhiteSpace(text))
        {
            int charLocation = text.IndexOf(stopAt, StringComparison.Ordinal);

            if (charLocation > 0)
            {
                return text.Substring(0, charLocation);
            }
        }

        return String.Empty;
    }
}

ผล:

223232
443
34443553
344

34

2
โปรดช่วยพวกเขาและเพิ่มการตรวจสอบข้อผิดพลาดด้วยโดยสมมติว่าเขามีแผนที่จะทำหน้าที่นี้ :)

ขอบคุณที่ฉันอยู่ใกล้สิ่งนี้ แต่อยากรู้ว่าใครมีวิธีอื่นที่จะทำนอกเหนือจากคำสั่งผสมนี้ แต่ใช่มันใช้งานได้ดีและยังค่อนข้างสั้น
PositiveGuy

14
หากคุณต้องการซับเดียวโดยไม่สูญเสียการตรวจสอบ "ไม่พบ" ที่เหมาะสมคุณสามารถทำสิ่งนี้ได้:string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
LukeH

2
แทนที่จะs.Substring(0, n)หนึ่งสามารถใช้s.Remove(n)เมื่อมันเป็นที่รู้จักกัน (เหมือนที่นี่) ที่มีความยาวของสตริงอย่างเคร่งครัดเกินs n
Jeppe Stig Nielsen

@LukeH ถ้า IndexOf ส่งกลับ -1 ในตัวอย่างของคุณสตริงว่างจะถูกส่งกลับใช่ไหม
ปิ๊ง

124

ใช้ฟังก์ชันแยก

static void Main(string[] args)
{
    string s = "223232-1.jpg";
    Console.WriteLine(s.Split('-')[0]);
    s = "443-2.jpg";
    Console.WriteLine(s.Split('-')[0]);
    s = "34443553-5.jpg";
    Console.WriteLine(s.Split('-')[0]);

Console.ReadKey();
}

หากสตริงของคุณไม่มี-คุณจะได้ทั้งสตริง


4
และถ้าคุณมียัติภังค์มากกว่าหนึ่งรายการคุณจะได้รับหลายองค์ประกอบในอาร์เรย์ของคุณ
James Dunne

2
อันที่จริงเจมส์ดังนั้นนี่จะเป็นทางออกก็ต่อเมื่อคุณคาดว่าจะมียัติภังค์เพียงตัวเดียว ฉันคิดว่าคุณสามารถใช้วิธี Linq เช่นการข้ามและการรวมเพื่อให้ได้สิ่งที่คุณต้องการ แต่คุณมีโค้ดมากกว่าวิธีการที่เสนอไปแล้ว ทั้งหมดขึ้นอยู่กับว่าคุณรู้เกี่ยวกับข้อมูลขาเข้ามากแค่ไหน
Dominic Cronin

7
และไม่กี่ปีต่อมาฉันเพิ่งตระหนักว่าฉันค่อนข้างเร็วเกินไปที่จะยอมรับประเด็นของเจมส์ คำถามจะถามวิธีค้นหาสตริงก่อนอักขระบางตัว ดังนั้นกรณีอื่น ๆ ของอักขระนั้นจึงไม่เกี่ยวข้องและการใช้ [0] จะ "ใช้ได้ผล" แน่นอนว่ายังคงขึ้นอยู่กับว่าเราเชื่อถือข้อมูลที่เข้ามามากแค่ไหน จะเกิดอะไรขึ้นถ้าไม่มี '-' เลย?
Dominic Cronin

1
ฉันคิดว่าจุด @JamesDunne คือการแบ่งออกเป็นอาร์เรย์คุณกำลังสร้างสตริงที่ไม่จำเป็นจำนวนมากซึ่งเป็นขยะที่ไม่จำเป็น
ปิ๊ง

1
ฉันคงไม่กังวลเรื่อง "ขยะที่ไม่จำเป็น" สตริงพิเศษใด ๆ ที่สร้างขึ้นด้วยวิธีนี้จะไม่สามารถเข้าถึงได้ในทันทีดังนั้นจึงถูกรวบรวมในรุ่น 0 ซึ่งเป็นค่าโสหุ้ยที่ต่ำมาก การออกแบบเครื่องเก็บขยะมีวัตถุประสงค์อย่างชัดเจนเพื่อให้สามารถใช้สิ่งของอายุสั้นจำนวนมากได้โดยแทบไม่มีค่าใช้จ่ายใด ๆ
Dominic Cronin

65
String str = "223232-1.jpg"
int index = str.IndexOf('-');
if(index > 0) {
    return str.Substring(0, index)
}

โหวตเพิ่มเพราะฉันต้องการทราบดัชนีของตัวคั่น
Piero Alberto

3
นี่เป็นคำตอบเดียวกับที่ Fredou ให้ไว้ (ปัจจุบันเป็นคำตอบยอดนิยม) ยกเว้นว่าจะละเว้นการจัดการกรณีที่ไม่พบรายการที่ตรงกัน
Dominic Cronin

7

มีการเปลี่ยนแปลงเล็กน้อยตั้งแต่กระทู้นี้เริ่มต้นขึ้น

ตอนนี้คุณสามารถใช้

string.Concat(s.TakeWhile((c) => c != '-'));

สิ่งนี้เปรียบเทียบประสิทธิภาพกับการรวมกันของ IndexOf และ Substring ที่ชัดเจนได้อย่างไร ฉันคิดว่ามันเป็นการต่อท้ายอักขระแต่ละตัวเข้ากับ StringBuilder จากนั้นสร้างสตริงในตอนท้าย นอกจากนี้ยังมีการเรียกใช้ฟังก์ชันสองอย่างผสมกันคงจะดีไม่น้อยถ้า Substring สามารถใช้ -1 เป็นอาร์กิวเมนต์ "length" ซึ่งหมายถึง "end of string"
ปิ๊ง

1
มันแย่กว่าสำหรับประสิทธิภาพ อย่างที่คุณพูดมันใช้ตัวสร้างสตริงและเมื่อตรวจสอบแล้วโค้ดดูเหมือนจะเรียก ToString บนอักขระแต่ละตัว จะชัดเจนกว่าหากคุณกำลังมองหาอักขระมากกว่าหนึ่งตัวเนื่องจากคุณสามารถเขียนแลมบ์ดาใหม่ได้อย่างง่ายดาย
Anthony Wieser

5

วิธีหนึ่งที่ทำได้คือใช้String.Substringร่วมกับString.IndexOf:

int index = str.IndexOf('-');
string sub;
if (index >= 0)
{
    sub = str.Substring(0, index);
}
else
{
    sub = ... // handle strings without the dash
}

เริ่มต้นที่ตำแหน่ง 0 ส่งคืนข้อความทั้งหมดเป็น แต่ไม่รวมถึงขีดกลาง


ถ้าดัชนี <= 0 คุณควรส่งคืน string.empty
ไม่คืนเงินไม่รับคืน

5
@NRNR: ถ้าคุณพูดอย่างนั้น OP รู้ข้อกำหนดทางธุรกิจไม่ใช่คุณหรือฉัน
Michael Petrotta

0

จากคำตอบของ BrainCore:

    int index = 0;   
    str = "223232-1.jpg";

    //Assuming we trust str isn't null 
    if (str.Contains('-') == "true")
    {
      int index = str.IndexOf('-');
    }

    if(index > 0) {
        return str.Substring(0, index);
    }
    else {
       return str;
    }

0

คุณสามารถใช้นิพจน์ทั่วไปเพื่อจุดประสงค์นี้ แต่ควรหลีกเลี่ยงข้อยกเว้นพิเศษเมื่อสตริงอินพุตไม่ตรงกันกับนิพจน์ทั่วไป

ก่อนอื่นเพื่อหลีกเลี่ยงอาการปวดหัวเป็นพิเศษในการหลีกเลี่ยงรูปแบบ regex - เราสามารถใช้ฟังก์ชันเพื่อจุดประสงค์นั้น:

String reStrEnding = Regex.Escape("-");

ฉันรู้ว่านี้ไม่ได้ทำอะไร - เป็น "-" เป็นเช่นเดียวแต่มันจะสร้างความแตกต่างเช่นถ้าเป็นตัวอักษรRegex.Escape("=") == "="@"\"

จากนั้นเราต้องจับคู่ตั้งแต่การขอสตริงจนถึงการสิ้นสุดสตริงหรือสลับกันหากไม่พบการสิ้นสุด - จากนั้นไม่จับคู่อะไรเลย (สตริงว่าง)

Regex re = new Regex("^(.*?)" + reStrEnding);

หากแอปพลิเคชันของคุณมีประสิทธิภาพที่สำคัญ - ให้แยกบรรทัดสำหรับ Regex ใหม่หากไม่เป็นเช่นนั้นคุณสามารถมีทุกอย่างในบรรทัดเดียว

และสุดท้ายจับคู่กับสตริงและแยกรูปแบบที่ตรงกัน:

String matched = re.Match(str).Groups[1].ToString();

และหลังจากนั้นคุณสามารถเขียนฟังก์ชันแยกกันเช่นเดียวกับที่ทำในคำตอบอื่นหรือเขียนฟังก์ชันแลมบ์ดาแบบอินไลน์ ฉันเขียนตอนนี้โดยใช้ทั้งสองสัญกรณ์ - ฟังก์ชันแลมบ์ดาแบบอินไลน์ (ไม่อนุญาตให้ใช้พารามิเตอร์เริ่มต้น) หรือการเรียกฟังก์ชันแยกกัน

using System;
using System.Text.RegularExpressions;

static class Helper
{
    public static string GetUntilOrEmpty(this string text, string stopAt = "-")
    {
        return new Regex("^(.*?)" + Regex.Escape(stopAt)).Match(text).Groups[1].Value;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Regex re = new Regex("^(.*?)-");
        Func<String, String> untilSlash = (s) => { return re.Match(s).Groups[1].ToString(); };

        Console.WriteLine(untilSlash("223232-1.jpg"));
        Console.WriteLine(untilSlash("443-2.jpg"));
        Console.WriteLine(untilSlash("34443553-5.jpg"));
        Console.WriteLine(untilSlash("noEnding(will result in empty string)"));
        Console.WriteLine(untilSlash(""));
        // Throws exception: Console.WriteLine(untilSlash(null));

        Console.WriteLine("443-2.jpg".GetUntilOrEmpty());
    }
}

Btw - การเปลี่ยนรูปแบบ regex เพื่อ"^(.*?)(-|$)"จะอนุญาตให้หยิบขึ้นมาได้จนกว่า"-"รูปแบบหรือหากไม่พบรูปแบบ - เลือกทุกอย่างจนจบสตริง


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.