จะแยกวิเคราะห์ชื่อเดือน (สตริง) เป็นจำนวนเต็มเพื่อเปรียบเทียบใน C # ได้อย่างไร?


94

ฉันต้องสามารถเปรียบเทียบชื่อเดือนที่ฉันมีในอาร์เรย์ได้

คงจะดีไม่น้อยหากมีทางตรงเช่น:

Month.toInt("January") > Month.toInt("May")

การค้นหา Google ของฉันดูเหมือนจะแนะนำวิธีเดียวคือการเขียนวิธีการของคุณเอง แต่ดูเหมือนว่าจะเป็นปัญหาทั่วไปที่ฉันคิดว่ามันจะถูกนำไปใช้แล้วใน. Net มีใครเคยทำมาก่อน

คำตอบ:


177

DateTime.ParseExact(monthName, "MMMM", CultureInfo.CurrentCulture ).Month

แม้ว่าเพื่อวัตถุประสงค์ของคุณคุณอาจจะดีกว่าเพียงแค่สร้างDictionary<string, int>การจับคู่ชื่อเดือนกับค่าของมัน


11
อย่าลืมพิจารณาstackoverflow.com/questions/258793/…เมื่อตัดสินใจว่าจะใช้ CultureInfo.CurrentCulture หรือ CultureInfo.InvariantCulture
Rasmus Faber


19

หากคุณใช้ - วิธีDateTime.ParseExact()ที่หลาย ๆ คนแนะนำคุณควรพิจารณาอย่างรอบคอบว่าคุณต้องการให้เกิดอะไรขึ้นเมื่อแอปพลิเคชันทำงานในสภาพแวดล้อมที่ไม่ใช่ภาษาอังกฤษ

ในเดนมาร์กซึ่งParseExact("Januar", ...)และParseExact("January", ...)ควรจะทำงานและที่ควรจะล้มเหลว?

ที่จะเป็นความแตกต่างระหว่างและCultureInfo.CurrentCultureCultureInfo.InvariantCulture


10

ทางออกง่ายๆอย่างหนึ่งคือสร้างพจนานุกรมที่มีชื่อและค่าต่างๆ จากนั้นใช้ประกอบด้วย () คุณจะพบค่าที่ถูกต้อง

Dictionary<string, string> months = new Dictionary<string, string>()
{
                { "january", "01"},
                { "february", "02"},
                { "march", "03"},
                { "april", "04"},
                { "may", "05"},
                { "june", "06"},
                { "july", "07"},
                { "august", "08"},
                { "september", "09"},
                { "october", "10"},
                { "november", "11"},
                { "december", "12"},
};
foreach (var month in months)
{
    if (StringThatContainsMonth.ToLower().Contains(month.Key))
    {
        string thisMonth = month.Value;
    }
}

9

คุณสามารถใช้เมธอด DateTime.Parse เพื่อรับอ็อบเจ็กต์ DateTime จากนั้นตรวจสอบคุณสมบัติ Month ทำสิ่งนี้:

int month = DateTime.Parse("1." + monthName + " 2008").Month;

เคล็ดลับคือการสร้างวันที่ที่ถูกต้องเพื่อสร้างวัตถุ DateTime


9

คุณสามารถใช้ enum ของเดือน:

public enum Month
{
    January,
    February,
    // (...)
    December,
}    

public Month ToInt(Month Input)
{
    return (int)Enum.Parse(typeof(Month), Input, true));
}

ฉันไม่แน่ใจ 100% เกี่ยวกับไวยากรณ์ของ enum.Parse () แม้ว่า


1
มันจะต้องเป็น "public Month ToInt (string Input) {... }" แต่อย่างอื่นถูกต้อง
James Curran

1
ฉันรู้ว่านี่เป็นความคิดเห็นเก่า แต่คิดว่าฉันจะชี้ให้เห็นว่าคุณควรเริ่ม enum จาก 1 เช่นpublic enum Month { January = 1, Feburary }และส่งไปยัง int แทน Month
eth0

@ eth0: อ๊ะ ... ถูกแล้ว แก้ไขแล้วขอบคุณที่ชี้ให้ดู ;-)
Treb

7

คุณไม่จำเป็นต้องสร้างอินสแตนซ์ DateTime เพื่อทำสิ่งนี้ ง่ายๆดังนี้:

public static class Month
{
    public static int ToInt(this string month)
    {
        return Array.IndexOf(
            CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
            month.ToLower(CultureInfo.CurrentCulture))
            + 1;
    }
}

ฉันใช้da-DKวัฒนธรรมดังนั้นการทดสอบหน่วยนี้จึงผ่าน:

[Theory]
[InlineData("Januar", 1)]
[InlineData("Februar", 2)]
[InlineData("Marts", 3)]
[InlineData("April", 4)]
[InlineData("Maj", 5)]
[InlineData("Juni", 6)]
[InlineData("Juli", 7)]
[InlineData("August", 8)]
[InlineData("September", 9)]
[InlineData("Oktober", 10)]
[InlineData("November", 11)]
[InlineData("December", 12)]
public void Test(string monthName, int expected)
{
    var actual = monthName.ToInt();
    Assert.Equal(expected, actual);
}

ฉันจะปล่อยให้มันเป็นแบบฝึกหัดสำหรับผู้อ่านเพื่อสร้างโอเวอร์โหลดที่คุณสามารถส่งผ่าน CultureInfo ที่ชัดเจนได้


การใช้งานที่ดีToLower()- ฉันไม่ทราบว่ามีการโอเวอร์โหลดอย่างใดอย่างหนึ่งแปลงสตริงusing the casing rules of the specified cultureแม้ว่าจะยุติธรรม แต่ก็ไม่ชัดเจนจากชื่อวิธีการที่อาจมีฟังก์ชันนั้น
David Clarke

1
โอเคฉันได้ทำการทดสอบโดยใช้ LINQPad และไม่สามารถใช้งานได้ในCurrentCultureไฟล์. ทั้ง"January".ToLower(CultureInfo.CurrentCulture).Dump();และ"January".ToLower(new CultureInfo("en-NZ")).Dump();เอาต์พุตjanuaryแต่ชื่อเดือนเป็นตัวพิมพ์ใหญ่ในไฟล์CurrentCulture.DateTimeFormat.MonthNames.
David Clarke

1
@DavidClarke ใช่คุณกำลังเรียกใช้ฟังก์ชันที่เรียกว่าToLower:) อันที่จริงมีข้อบกพร่องเชิงตรรกะเล็กน้อยในรหัสของฉันเนื่องจากชื่อเดือนจะได้รับเป็นตัวพิมพ์เล็กทั้งหมดใน da-DK ดังนั้นไม่ควรใช้ตัวพิมพ์เล็กและตัวพิมพ์เล็กของอินพุตหรือมิฉะนั้นก็ควรใช้ตัวพิมพ์เล็กของชื่อเดือนทั้งหมด - ขึ้นอยู่กับว่าต้องการจับคู่แบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่หรือไม่
Mark Seemann

1
ใช่ฉันกำลังตีความเอกสารusing the casing rules of the specified cultureเพื่อหมายความว่าจะใช้ตัวพิมพ์ใหญ่เช่นเดือนและวันต่อCultureInfo. ซึ่งใช้ได้กับตัวอย่างของคุณเนื่องจากชื่อเดือนเป็นตัวพิมพ์เล็ก การสาธิตที่มีประสิทธิภาพในการใช้การทดสอบหน่วยเพื่อทำให้เข้าใจผิด อาจมีค่าควรแก่การแก้ไขเพื่อให้ชัดเจนว่าตัวอย่างของคุณเป็นกรณีขอบ :-)
David Clarke

2

และการตอบคำถามเจ็ดปีหลังจากที่ถามคำถามนี้เป็นไปได้ที่จะทำการเปรียบเทียบนี้โดยใช้วิธีการในตัว:

Month.toInt("January") > Month.toInt("May")

กลายเป็น

Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
                 t => t.Equals("January", StringComparison.CurrentCultureIgnoreCase)) >
Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
                 t => t.Equals("May", StringComparison.CurrentCultureIgnoreCase))

ซึ่งสามารถปรับโครงสร้างใหม่เป็นวิธีการขยายเพื่อความเรียบง่าย ต่อไปนี้เป็นตัวอย่าง LINQPad (ดังนั้นDump()วิธีการเรียกใช้):

void Main()
{
    ("January".GetMonthIndex() > "May".GetMonthIndex()).Dump();
    ("January".GetMonthIndex() == "january".GetMonthIndex()).Dump();
    ("January".GetMonthIndex() < "May".GetMonthIndex()).Dump();
}

public static class Extension {
    public static int GetMonthIndex(this string month) {
        return Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
                         t => t.Equals(month, StringComparison.CurrentCultureIgnoreCase));
    }
}

พร้อมเอาต์พุต:

False
True
True

นี่เป็นทางออกที่ดีกว่ามากโดยใช้การเปรียบเทียบสตริง IgnoreCase วิธีนี้ใช้ได้ดีกับคำถามของ OP อย่างไรก็ตามหากคุณต้องการใช้วิธีนี้ในการแปลงเป็นค่าเดียวกันที่ส่งคืนโดย DateTime เดือนฉันขอแนะนำให้เพิ่ม +1 ให้กับผลลัพธ์ ข้อกำหนดการเปรียบเทียบของ OP ยังคงเป็นที่พอใจหรือแน่นอน
iGanja

1

หากคุณใช้ c # 3.0 (หรือสูงกว่า) คุณสามารถใช้ส่วนขยายได้


ถ้าอย่างนั้นฉันก็คิดว่าวิธีการของคุณจะเป็นทางออกที่ดีที่สุด
Adam Naylor

1
@AdamNaylor: Extenders คืออะไร? คุณช่วยอธิบายคำตอบพร้อมตัวอย่างได้ไหม
Amir

1
Public Function returnMonthNumber(ByVal monthName As String) As Integer
    Select Case monthName.ToLower
        Case Is = "january"
            Return 1
        Case Is = "february"
            Return 2
        Case Is = "march"
            Return 3
        Case Is = "april"
            Return 4
        Case Is = "may"
            Return 5
        Case Is = "june"
            Return 6
        Case Is = "july"
            Return 7
        Case Is = "august"
            Return 8
        Case Is = "september"
            Return 9
        Case Is = "october"
            Return 10
        Case Is = "november"
            Return 11
        Case Is = "december"
            Return 12
        Case Else
            Return 0
    End Select
End Function

รหัสข้อควรระวังอยู่ในเวอร์ชันเบต้า


คำตอบที่ได้รับการยอมรับนั้นดีกว่ามาก
James A Mohler

1

ฉันแปลเป็นรหัส C # ในเวอร์ชันภาษาสเปนเกี่ยวกับ:

public string ObtenerNumeroMes(string NombreMes){

       string NumeroMes;   

       switch(NombreMes) {

        case ("ENERO") :
            NumeroMes = "01";
            return NumeroMes;

        case ("FEBRERO") :
            NumeroMes = "02";
            return NumeroMes;

        case ("MARZO") :
            NumeroMes = "03";
            return NumeroMes;

        case ("ABRIL") :
            NumeroMes = "04";
            return NumeroMes;

        case ("MAYO") :
            NumeroMes = "05";
            return NumeroMes;

        case ("JUNIO") :
            NumeroMes = "06";
            return NumeroMes;

        case ("JULIO") :
            NumeroMes = "07";
            return NumeroMes;

        case ("AGOSTO") :
            NumeroMes = "08";
            return NumeroMes;

        case ("SEPTIEMBRE") :
            NumeroMes = "09";
            return NumeroMes;

        case ("OCTUBRE") :
            NumeroMes = "10";
            return NumeroMes;

        case ("NOVIEMBRE") :
            NumeroMes = "11";
            return NumeroMes;

        case ("DICIEMBRE") :
            NumeroMes = "12";
            return NumeroMes;

            default:
            Console.WriteLine("Error");
            return "ERROR";

        }

   }

0

สิ่งที่ฉันทำคือใช้ SimpleDateFormat เพื่อสร้างสตริงรูปแบบและแยกวิเคราะห์ข้อความเป็นวันที่จากนั้นดึงข้อมูลเดือนจากนั้น รหัสอยู่ด้านล่าง:

int year = 2012 \\or any other year
String monthName = "January" \\or any other month
SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yyyy");
int monthNumber = format.parse("01-" + monthName + "-" + year).getMonth();

0

รหัสนี้ช่วยคุณ ...

using System.Globalization;

....

string FullMonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(DateTime.UtcNow.Month);

GetMonthName Method - ส่งคืนสตริง ...

หากคุณต้องการรับเดือนเป็นจำนวนเต็มให้ใช้ -

DateTime dt= DateTime.UtcNow;
int month= dt.Month;

หวังว่าจะช่วยคุณได้ !!!

ขอบคุณ !!!

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