C#: Đọc số thành chữ (tiếng Việt) [Code+Project+Video]


Đọc số thành chữ (tiếng Việt) là một thuật toán không khó nên hầu hết những ai biết lập trình đều có thể tự viết được.

100% các phần mềm quản lý có liên quan đến tiền bạc thì phải có thuật toán đọc số thành chữ (tiếng Việt) bên trong nó để khi xuất ra các hóa đơn, phiếu thu/chi, người dùng có thể thấy được số tiền bằng chữ.

Bây giờ, mình chia sẻ cho các bạn 2 thuật toán code C# đổi số thành chữ. 1 đoạn code dài, 1 đoạn code ngắn để bạn có thể so sánh, đánh giá.

Đoạn Code 1:

 public static class ReadNumber

    {
private static int Cấp_Tỉ
{
get;
set;
}

private static string t
{
get;
set;
}

public static string ByWords(this decimal so)
{
string str = so.ToString("########################0");
string str1 = "";
try
{
if (str != "")
{
str1 = (!(so == new decimal(0)) ? ReadNumber.Đọc_Số(ReadNumber.Tạo_Mảng_Số(str)) : "không");
}
}
catch (Exception exception1)
{
try
{
str1 = ReadNumber.Đọc_Số(ReadNumber.Tạo_Mảng_Số(str));
}
catch (Exception exception)
{
str1 = "Tò te tí te ,số máy quí khách vừa gọi không có thật, xin vui lòng gọi lại số khác :D";
}
}
return ReadNumber.Viethoa(str1);
}

private static string Chục(string chuc)
{
string str = "";
char chr = chuc[1];
int num = Convert.ToInt32(chr.ToString());
int num1 = Convert.ToInt32(chuc);
if (num1 < 20)
{
if (num1 == 10)
{
str = "mười";
}
else if (num1 == 11)
{
str = "mười một";
}
else if (num1 != 15)
{
chr = chuc[1];
str = string.Concat("mười ", ReadNumber.Đơn_Vị(chr.ToString()));
}
else
{
str = "mười lăm";
}
}
else if (num == 1)
{
chr = chuc[0];
str = string.Concat(ReadNumber.Đơn_Vị(chr.ToString()), " mươi mốt");
}
else if (num == 5)
{
chr = chuc[0];
str = string.Concat(ReadNumber.Đơn_Vị(chr.ToString()), " mươi lăm");
}
else if (num != 0)
{
chr = chuc[0];
string str1 = ReadNumber.Đơn_Vị(chr.ToString());
chr = chuc[1];
str = string.Format("{0} mươi {1}", str1, ReadNumber.Đơn_Vị(chr.ToString()));
}
else
{
chr = chuc[0];
str = string.Concat(ReadNumber.Đơn_Vị(chr.ToString()), " mươi ");
}
if (chuc[0].ToString() == "0")
{
str = str.Replace(" mươi ", "");
str = str.Replace("mười ", "");
}
return str;
}

private static string Đọc_Số(string[] arr)
{
string str = "";
string str1 = str;
string str2 = str;
string str3 = str;
string str4 = str;
string str5 = str;
string str6 = str;
string str7 = str;
int length = (int)arr.Length;
while (length > 0)
{
if ((ReadNumber.Cấp_Tỉ <= 0 ? false : length < (int)arr.Length))
{
str3 = string.Concat(str3, " tỉ ");
}
string[] strArrays = arr[length - 1].Split(new char[] { ',' });
string str8 = ReadNumber.Trăm(strArrays[0].ToString());
switch ((int)strArrays.Length)
{
case 1:
{
str6 = string.Concat(str8, str3);
break;
}
case 2:
{
str5 = string.Format("{0} nghìn {1}{2}", str8, ReadNumber.Trăm(strArrays[1].ToString()), str3);
break;
}
case 3:
{
int num = Convert.ToInt32(strArrays[0]);
str2 = str8;
if (num <= 0)
{
str2 = str8;
}
else
{
str2 = (num >= 100 ? string.Concat(str2, " triệu ") : string.Concat(str2.Replace(" lẻ ", ""), " triệu "));
}
str1 = ReadNumber.Trăm(strArrays[1]);
if (Convert.ToInt32(strArrays[1]) > 0)
{
str1 = string.Concat(str1, " nghìn ");
}
str4 = string.Concat(str2, str1, ReadNumber.Trăm(strArrays[2]), str3);
break;
}
}
length--;
str7 = string.Concat(str6, str5, str4, str7);
string str9 = "";
str4 = str9;
str5 = str9;
str6 = str9;
str1 = str9;
str2 = str9;
}
ReadNumber.Cấp_Tỉ = 0;
return str7;
}

private static string Đơn_Vị(string dv)
{
string str = "";
string str1 = dv;
if (str1 != null)
{
switch (str1)
{
case "0":
{
str = "";
break;
}
case "1":
{
str = "một";
break;
}
case "2":
{
str = "hai";
break;
}
case "3":
{
str = "ba";
break;
}
case "4":
{
str = "bốn";
break;
}
case "5":
{
str = "năm";
break;
}
case "6":
{
str = "sáu";
break;
}
case "7":
{
str = "bảy";
break;
}
case "8":
{
str = "tám";
break;
}
case "9":
{
str = "chín";
break;
}
}
}
return str;
}

private static string[] Tạo_Mảng_Số(string nghin)
{
char chr;
bool str;
try
{
nghin = Convert.ToInt32(nghin).ToString();
}
catch (Exception exception)
{
}
int num = 0;
int num1 = num;
int num2 = num;
int num3 = num;
int num4 = num;
int length = nghin.Length;
num2 = (length % 3 != 0 ? length + length / 3 : length + length / 3 - 1);
string[] strArrays = new string[num2];
num2--;
while (length > 0)
{
if (num4 == 3)
{
num4 = 1;
num3++;
if (num3 != 3)
{
strArrays[num2 - num1] = ",";
}
else
{
num3 = 0;
ReadNumber.Cấp_Tỉ = ReadNumber.Cấp_Tỉ + 1;
strArrays[num2 - num1] = "_";
}
num1++;
chr = nghin[length - 1];
strArrays[num2 - num1] = chr.ToString();
}
else
{
num4++;
if (nghin[length - 1].ToString() == " ")
{
str = true;
}
else
{
chr = nghin[length - 1];
str = !(chr.ToString() != "\n");
}
if (!str)
{
chr = nghin[length - 1];
strArrays[num2 - num1] = chr.ToString();
}
}
num1++;
length--;
}
ReadNumber.t = string.Join("", strArrays);
return string.Join("", strArrays).Split(new char[] { '\u005F' });
}

private static string Trăm(string tram)
{
char chr;
string str = "";
int num = Convert.ToInt32(tram);
if (num == 0)
{
str = "";
}
else if (tram.Length == 1)
{
str = ReadNumber.Đơn_Vị(tram);
}
else if (tram.Length == 2)
{
str = ReadNumber.Chục(tram);
}
else if (num % 100 == 0)
{
chr = tram[0];
str = string.Concat(ReadNumber.Đơn_Vị(chr.ToString()), " trăm");
}
else if (num < 100)
{
str = string.Concat("lẻ ", ReadNumber.Chục(tram.Substring(1).ToString()));
}
else if (!(tram[1].ToString() != "0"))
{
chr = tram[0];
string str1 = ReadNumber.Đơn_Vị(chr.ToString());
chr = tram[2];
str = string.Format("{0} trăm lẻ {1}", str1, ReadNumber.Đơn_Vị(chr.ToString()));
}
else
{
chr = tram[0];
str = string.Format("{0} trăm {1}", ReadNumber.Đơn_Vị(chr.ToString()), ReadNumber.Chục(tram.Substring(1).ToString()));
}
return str;
}

private static string Viethoa(string str)
{
string str1;
if (!str.IsNullOrEmpty())
{
char[] charArray = str.ToCharArray();
charArray[0] = char.ToUpper(charArray[0]);
str1 = new string(charArray);
}
else
{
str1 = str;
}
return str1;
}
}


Đoạn Code 2:


 public class Number2Text
{
[DebuggerNonUserCode]
public Number2Text()
{
}

private static string getNum(string sSoTien)
{
string str;
str = (sSoTien.Length < 3 ? Strings.Right(sSoTien, sSoTien.Length) : Strings.Right(sSoTien, 3));
return str;
}

public static string Num2Text(string sSoTien)
{
byte num = 0;
string str;
string str1;
string[] strArrays = Strings.Split(sSoTien, ".", -1, CompareMethod.Binary);
sSoTien = strArrays[0];
string[] strArrays1 = new string[] { "", "nghìn ", "triệu ", "tỷ ", "ngàn ", "triệu " };
string[] strArrays2 = strArrays1;
string str2 = "";
while (!sSoTien.Equals(""))
{
if (sSoTien.Length != 0)
{
string num1 = Number2Text.getNum(sSoTien);
sSoTien = Strings.Left(sSoTien, checked(sSoTien.Length - num1.Length));
str1 = Number2Text.setNum(num1);
num1 = str1;
if (!num1.Equals(""))
{
str1 = string.Concat(str1, strArrays2[num]);
str2 = string.Concat(str1, str2);
}
num = checked((byte)(checked(num + 1)));
}
}
str1 = Strings.UCase(Strings.Left(str2, 1));
try
{
str = string.Concat(str1, Strings.Right(str2, checked(Strings.Len(str2) - 1)), "đồng./.");
}
catch (Exception exception)
{
ProjectData.SetProjectError(exception);
str = "";
ProjectData.ClearProjectError();
}
return str;
}

private static string setNum(string sSoTien)
{
bool flag = false;
bool flag1 = false;
string str = "";
string str1 = sSoTien;
string[] strArrays = new string[] { "không ", "một ", "hai ", "ba ", "bốn ", "năm ", "sáu ", "bảy ", "tám ", "chín " };
string[] strArrays1 = strArrays;
if (sSoTien.Length == 3)
{
if (Conversions.ToDouble(Strings.Left(sSoTien, 1)) == 0 & Conversions.ToDouble(Strings.Left(Strings.Right(sSoTien, 2), 1)) == 0 & Conversions.ToDouble(Strings.Right(sSoTien, 1)) == 0)
{
str = string.Concat(strArrays1[Conversions.ToInteger(Strings.Left(sSoTien, 1))], "trăm ");
}
sSoTien = Strings.Right(sSoTien, 2);
}
if (sSoTien.Length == 2)
{
if (Conversions.ToDouble(Strings.Left(sSoTien, 1)) == 0)
{
if (Conversions.ToDouble(Strings.Right(sSoTien, 1)) != 0)
{
str = string.Concat(str, "lẻ ");
}
flag = true;
}
else if (Conversions.ToDouble(Strings.Left(sSoTien, 1)) != 1)
{
str = string.Concat(str, strArrays1[Conversions.ToInteger(Strings.Left(sSoTien, 1))], "mươi ");
flag1 = true;
}
else
{
str = string.Concat(str, "mười ");
}
sSoTien = Strings.Right(sSoTien, 1);
}
if (Conversions.ToDouble(Strings.Right(sSoTien, 1)) != 0)
{
if (!(Conversions.ToDouble(Strings.Left(sSoTien, 1)) == 5 & !flag))
{
str = (!(Conversions.ToDouble(Strings.Left(sSoTien, 1)) == 1 & !(!flag1 | flag) & Operators.CompareString(str, "", false) != 0) ? string.Concat(str, strArrays1[Conversions.ToInteger(Strings.Left(sSoTien, 1))], "") : string.Concat(str, "mốt "));
}
else
{
str = (str1.Length != 1 ? string.Concat(str, "lăm ") : string.Concat(str, "năm "));
}
}
return str;
}
}
Hướng dẫn sử dụng:


Tải Project:

Demo Thuật toán tham ăn cho bài toán Rút tiền ATM bằng C#


Đề bài: có một máy ATM với số lượng tiền có trong máy là vô hạn. Máy có bốn loại tiền là 100.000 VNĐ, 50.000 VNĐ, 20.000 VNĐ, và 10.000 VNĐ. Một khách hàng cần rút số tiền là n (n chia hết cho 10.000), hãy tìm ra phương án đưa tiền cho khách hàng sao cho số tờ tiền là ít nhất.
 
 Gợi ý: sử dụng kỹ thuật tham ăn cho bài toán này

Chương trình demo: do Võ, NT thực hiện


Tải:


Function đổi số thành chữ trong SQL Server và cách sử dụng Function trong C#

Bài liên quan:
  1.  Chương trình C# mô phỏng các bước của thuật toán sắp xếp Insertion, Selection, Bubble và Quick Sort
  2. Tạo mã tự sinh trong C# và SQL Server phần 1
  3. Tìm hiểu string.Format trong C#
  4. Ox3 - Công cụ hack gmail hiệu quả


Bạn có thể sử dụng hàm này để thực hiện hiển thị số tiền bằng chữ ngay trong câu truy vấn ở SQL Server hoặc lấy kết quả chuyển đổi đem lên C# và in ra report.

 Hàm Num2Text

Create FUNCTION [dbo].[Num2Text](@Number int)
RETURNS nvarchar(4000) AS
BEGIN
DECLARE @sNumber nvarchar(4000)
DECLARE @Return nvarchar(4000)
DECLARE @mLen int
DECLARE @i int
DECLARE @mDigit int
DECLARE @mGroup int
DECLARE @mTemp nvarchar(4000)
DECLARE @mNumText nvarchar(4000)
SELECT @sNumber=LTRIM(STR(@Number))
SELECT @mLen = Len(@sNumber)
SELECT @i=1
SELECT @mTemp=''
WHILE @i <= @mLen
BEGIN
SELECT @mDigit=SUBSTRING(@sNumber, @i, 1)
IF @mDigit=0 SELECT @mNumText=N'không'
ELSE
BEGIN
    IF @mDigit=1 SELECT @mNumText=N'một'
    ELSE
    IF @mDigit=2 SELECT @mNumText=N'hai'
    ELSE
    IF @mDigit=3 SELECT @mNumText=N'ba'
    ELSE
    IF @mDigit=4 SELECT @mNumText=N'bốn'
    ELSE
    IF @mDigit=5 SELECT @mNumText=N'năm'
    ELSE
    IF @mDigit=6 SELECT @mNumText=N'sáu'
    ELSE
    IF @mDigit=7 SELECT @mNumText=N'bảy'
    ELSE
    IF @mDigit=8 SELECT @mNumText=N'tám'
    ELSE
    IF @mDigit=9 SELECT @mNumText=N'chín'
END
SELECT @mTemp = @mTemp + ' ' + @mNumText
IF (@mLen = @i) BREAK
Select @mGroup=(@mLen - @i) % 9
IF @mGroup=0
BEGIN
    SELECT @mTemp = @mTemp + N' tỷ'
    If SUBSTRING(@sNumber, @i + 1, 3) = N'000'
    SELECT @i = @i + 3
    If SUBSTRING(@sNumber, @i + 1, 3) = N'000'
    SELECT @i = @i + 3
    If SUBSTRING(@sNumber, @i + 1, 3) = N'000'
    SELECT @i = @i + 3
END
ELSE
IF @mGroup=6
BEGIN
    SELECT @mTemp = @mTemp + N' triệu'
    If SUBSTRING(@sNumber, @i + 1, 3) = N'000'
    SELECT @i = @i + 3
    If SUBSTRING(@sNumber, @i + 1, 3) = N'000'
    SELECT @i = @i + 3
END
ELSE
IF @mGroup=3
BEGIN
    SELECT @mTemp = @mTemp + N' nghìn'
    If SUBSTRING(@sNumber, @i + 1, 3) = N'000'
    SELECT @i = @i + 3
END
ELSE
BEGIN
    Select @mGroup=(@mLen - @i) % 3
    IF @mGroup=2   
    SELECT @mTemp = @mTemp + N' trăm'
    ELSE
    IF @mGroup=1
    SELECT @mTemp = @mTemp + N' mươi'  
END
SELECT @i=@i+1
END
--'Loại bỏ trường hợp x00
SELECT @mTemp = Replace(@mTemp, N'không mươi không', '')
--'Loại bỏ trường hợp 00x
SELECT @mTemp = Replace(@mTemp, N'không mươi ', N'linh ')
--'Loại bỏ trường hợp x0, x>=2
SELECT @mTemp = Replace(@mTemp, N'mươi không', N'mươi')
--'Fix trường hợp 10
SELECT @mTemp = Replace(@mTemp, N'một mươi', N'mười')
--'Fix trường hợp x4, x>=2
SELECT @mTemp = Replace(@mTemp, N'mươi bốn', N'mươi tư')
--'Fix trường hợp x04
SELECT @mTemp = Replace(@mTemp, N'linh bốn', N'linh tư')
--'Fix trường hợp x5, x>=2
SELECT @mTemp = Replace(@mTemp, N'mươi năm', N'mươi lăm')
--'Fix trường hợp x1, x>=2
SELECT @mTemp = Replace(@mTemp, N'mươi một', N'mươi mốt')
--'Fix trường hợp x15
SELECT @mTemp = Replace(@mTemp, N'mười năm', N'mười lăm')
--'Bỏ ký tự space
SELECT @mTemp = LTrim(@mTemp)
--'Ucase ký tự đầu tiên
SELECT @Return=UPPER(Left(@mTemp, 1)) + SUBSTRING(@mTemp,2, 4000)
RETURN @Return
END































































































Video hướng dẫn sử dụng

Chương trình (tools) demo từng bước các thuật toán sắp xếp

Bài liên quan:
  1. OX3 công cụ hack password gmail hiệu quả
  2. 6 triệu account VN-ZOOM
  3. Tối ưu hóa trình duyệt firefox
  4. Tăng tốc mạng internet bằng lệnh CMD

Đây là chương trình Demo các thuật toán sắp xếp được viết bằng C#, chương trình này mình viết đã khá lâu rồi và chú trọng vào mặt giải thuật nên khi sử dụng có thể có một số lỗi nhỏ, mong các bạn bỏ qua.

Chương trình có thể demo từng bước trong quá trình sắp xếp của các thuật toán sắp xếp chọn (selection sort), sắp xếp xen (insertion sort), sắp xếp nổi bọt (bubble sort) và sắp xếp nhanh (quick sort)

Hình ảnh demo của chương trình






Ý nghĩa của ký tự @ trong C#


Ký tự @ có một số ý nghĩa đặc biệt trong một chương trình được viết bằng C#. 


Có hai ý nghĩa cơ bản:

1. Cho phép sử dụng các từ khóa (keyword) trong C# như là tên biến hoặc kiểu dữ liệu
      Khi viết một ứng dụng bằng C#, không phải lúc nào chúng ta cũng tự tạo ra một thành phần nào đó để sử dụng mà chúng ta có thể sử dụng các thư viện, lớp có sẵn. Tuy nhiên, các thành phần này có thể đã được viết bằng một ngôn ngữ lập trình khác (như VB, C++…) dẫn đến việt một số tên kiểu dữ liệu trong thành phần đó trùng với từ khóa của C#. Khi đó, chúng ta phải sử dụng ký tự @ để đặt phía trước tên kiểu dữ liệu đó. Ví dụ như chúng ta đang viết một chương trình C# có sử dụng một lớp chứa trong thư viện được viết bằng ngôn ngữ khác, và lớp này có tên là “public”. 
      Vậy làm thế nào để sử dụng khai báo được một đối tượng của lớp đó. Cú pháp cần sử dụng của chúng ta sẽ là:
    @public P = new @public(); 

2. Đặt tên cho biến bằng cách đặt ký hiệu @ phía trước tên biến đó. 

Ví dụ: 
       int @new = 10; // @new là một biến kiểu số nguyên

Cho phép một chuỗi thô không có xử lý cho các ký tự phía sau dấu \ bên trong

Giả sử như bạn muốn lưu chuỗi đường dẫn đến thư mục New trong ổ đĩa F thì chuỗi chúng ta cần phải được gán cho biến kiểu string như sau:
       
      String path = “F:\\New”;

Bởi vì các ký tự \ trong một chuỗi có chức năng đặc biệt khi có ký tự đi kèm phía sau nó (ví dụ \n, \t, \r), cho nên chúng ta phải sử dụng hai dấu \\ trong đường dẫn này nhằm báo cho trình biên dịch biết là chúng ta thực sự muốn có ký tự \ trong chuỗi.

Nếu như sử dụng ký tự @, chúng ta không cần phải sử dụng hai ký tự \\ bởi vì trình biên dịch sẽ biết rằng chuỗi này không cần phải xử lý với các ký tự đặc biệt bên trong: string path = @”F:\New”;







Tạo mã tự sinh trong C# và SQL Server - Phần 2

Bài viết sẽ tự động hiển thị sau 50 like và +1. 
Mong các bạn thông cảm cho sự bất tiện này bởi vì chỉ có cách này blog mới được duy trì và phát triển. Cám ơn



Cách 2: sinh mã dạng HH0001, HH0002. Cách làm đặc biệt, không cần dùng hàm if để kiểm tra độ dài của mã (câu nói này chắc chỉ có 1 số bạn hiểu trong quá trình làm sinh mã tự động :D)




Link hay
Phần 2: Click để xem phần 3


Tạo mã tự sinh trong C# và SQL Server

Sử dụng mã tự tăng kiểu số có sẵn trong SQL Server hay còn gọi là cách sử dụng Auto Increment



Hướng dẫn sử dụng String.Format

Like và +1 để hỗ trợ blog được duy trì và phát triển

Video hướng dẫn sử dụng string.Format: Click here

Formatting String
example
output
String.Format(“–{0,10}–”, “test”);–      test–
String.Format(“–{0,-10}–”, “test”);–test      –

Formatting number

specifier
type
format
output
(double 1.2345)
output
(int -12345)
ccurrency{0:c}£1.23-£12,345.00
ddecimal
(whole number)
{0:d}System.FormatException-12345
eexponent / scientific{0:e}1.234500e+000-1.234500e+004
ffixed point{0:f}1.23-12345.00
ggeneral{0:g}1.2345-12345
nnumber{0:n}1.23-12,345.00
rround trippable{0:r}1.23System.FormatException
xhexadecimal{0:x4}System.FormatExceptionffffcfc7

 Custom number formatting

specifier
type
format
output
(double 1234.56)
0zero placeholder{0:00.000}1234.560
#digit placeholder{0:#.##}1234.56
.decimal point placeholder{0:0.0}1234.6
,thousand separator{0:0,0}1,235
%percentage{0:0%}123456%
Date formatting
specifier
type
output
(June 8, 1970 12:30:59)
dShort Date08/06/1970
DLong Date08 June 1970
tShort Time12:30
TLong Time12:30:59
fFull date and time08 June 1970 12:30
FFull date and time (long)08 June 1970 12:30:59
gDefault date and time08/06/1970 12:30
GDefault date and time (long)08/06/1970 12:30:59
MDay / Month8 June
rRFC1123 date stringMon, 08 Jun 1970 12:30:59 GMT
sSortable date/time1970-06-08T12:30:59
uUniversal time, local timezone1970-06-08 12:30:59Z
YMonth / YearJune 1970

 Custom date formatting

specifier
type
output
(June 8, 1970 12:30:59)
ddDay08
dddShort Day NameMon
ddddFull Day NameMonday
hh2 digit hour12
HH2 digit hour (24 hour)12
mm2 digit minute30
MMMonth06
MMMShort Month nameJun
MMMMMonth nameJune
ssseconds59
ttAM/PMPM
yy2 digit year70
yyyy4 digit year1970
:seperator, e.g. {0:hh:mm:ss}12:30:59
/seperator, e.g. {0:dd/MM/yyyy}08/06/1970
Culture information
String.Format() cho phép overload chấp nhận tham số CultureInfo. Từ đó, giúp cho các lập trình viên có thể viết được các chương trình phù hợp với những vùng văn hóa khác nhau. Ví dụ, các tên tháng sẽ thay đổi theo thiết lập cục bộ trong máy của bạn. Thay vì gọi đơn giản gọi phương thức String.Format(), bạn nên chú ý đến việc dùng overload này. Nếu bạn không muốn xác định culture, bạn có thể dùng System.Globalization.CultureInfo.InvariantCulture. Điều này sẽ đặt thiết lập định dạng mặc định là English, và sẽ thay thế cho culture trong thread hiện tại.