Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใช้ unicode() ใน SQLite บน Android

การใช้ฟังก์ชัน unicode() ใน SQLite บน Android

ฟังก์ชัน unicode() ใน SQLite คืนค่า Unicode Code Point (ตัวเลขจำนวนเต็ม) ของตัวอักษรตัวแรกในสตริงที่ระบุ ใช้สำหรับตรวจสอบค่า Unicode ของตัวอักษร

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

สร้างโปรเจกต์ Android ใหม่ใน Android Studio

ขั้นตอนที่ 2: ออกแบบ Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/etName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ป้อนชื่อ" />

    <EditText
        android:id="@+id/etSalary"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ป้อนเงินเดือน"
        android:inputType="numberDecimal" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:orientation="horizontal">
        <Button android:id="@+id/btnSave" android:text="บันทึก" android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btnRefresh" android:text="รีเฟรช" android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btnUpdate" android:text="อัปเดต" android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btnDelete" android:text="ลบทั้งหมด" android:layout_width="wrap_content" android:layout_height="wrap_content" />
    </LinearLayout>

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp">
    </ListView>
</LinearLayout>

ขั้นตอนที่ 3: MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private EditText etName, etSalary;
    private ListView listView;
    private ArrayAdapter<String> adapter;
    private DatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dbHelper = new DatabaseHelper(this);
        ArrayList<String> dataList = dbHelper.getUnicodeValues();

        etName = findViewById(R.id.etName);
        etSalary = findViewById(R.id.etSalary);
        listView = findViewById(R.id.listView);

        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList);
        listView.setAdapter(adapter);

        findViewById(R.id.btnDelete).setOnClickListener(v -> {
            Toast.makeText(this, dbHelper.deleteAll() ? "ลบสำเร็จ" : "ลบไม่สำเร็จ", Toast.LENGTH_LONG).show();
        });

        findViewById(R.id.btnUpdate).setOnClickListener(v -> {
            String name = etName.getText().toString().trim();
            String salary = etSalary.getText().toString().trim();
            if (!name.isEmpty() && !salary.isEmpty()) {
                Toast.makeText(this, dbHelper.update(name, salary) ? "อัปเดตสำเร็จ" : "อัปเดตไม่สำเร็จ", Toast.LENGTH_LONG).show();
            } else {
                etName.setError("กรุณาป้อนชื่อ");
                etSalary.setError("กรุณาป้อนเงินเดือน");
            }
        });

        findViewById(R.id.btnRefresh).setOnClickListener(v -> {
            dataList.clear();
            dataList.addAll(dbHelper.getUnicodeValues());
            adapter.notifyDataSetChanged();
        });

        findViewById(R.id.btnSave).setOnClickListener(v -> {
            String name = etName.getText().toString().trim();
            String salary = etSalary.getText().toString().trim();
            if (!name.isEmpty() && !salary.isEmpty()) {
                Toast.makeText(this, dbHelper.insert(name, salary) ? "บันทึกสำเร็จ" : "บันทึกไม่สำเร็จ", Toast.LENGTH_LONG).show();
            } else {
                etName.setError("กรุณาป้อนชื่อ");
                etSalary.setError("กรุณาป้อนเงินเดือน");
            }
        });
    }
}

ขั้นตอนที่ 4: DatabaseHelper.java - ใช้ unicode() ใน Query

package com.example.myapplication;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;

public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "salaryDatabase";
    private static final String TABLE_NAME = "SalaryDetails";
    private static final int DB_VERSION = 1;

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                     "name TEXT, salary REAL, datetime DEFAULT CURRENT_TIMESTAMP)";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }

    public boolean insert(String name, String salary) {
        SQLiteDatabase db = getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("salary", salary);
        return db.insert(TABLE_NAME, null, values) != -1;
    }

    // จุดสำคัญ: ใช้ unicode(name) ได้ Code Point ของตัวอักษรแรก
    public ArrayList<String> getUnicodeValues() {
        SQLiteDatabase db = getReadableDatabase();
        ArrayList<String> list = new ArrayList<>();
        
        // unicode(X) คืนค่า Code Point ของตัวอักษรตัวแรกของ X
        Cursor cursor = db.rawQuery(
            "SELECT name, unicode(name) as unicode_value FROM " + TABLE_NAME, null);

        if (cursor.moveToFirst()) {
            do {
                String name = cursor.getString(0);
                int codePoint = cursor.getInt(1);
                list.add(String.format("%s → U+%04X (%d)", name, codePoint, codePoint));
            } while (cursor.moveToNext());
        }
        cursor.close();
        return list;
    }

    public boolean update(String name, String salary) {
        SQLiteDatabase db = getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("salary", salary);
        return db.update(TABLE_NAME, values, "name = ?", new String[]{name}) > 0;
    }

    public boolean deleteAll() {
        return getWritableDatabase().delete(TABLE_NAME, null, null) > 0;
    }
}

คำอธิบาย unicode()

unicode(X)
  • คืนค่า Unicode Code Point (Integer) ของตัวอักษรตัวแรกในสตริง X
  • หาก X เป็น NULL หรือ Empty String → คืนค่า NULL
  • ทำงานกับ UTF-8/UTF-16 ภายใน SQLite Engine
  • คู่กับ char() - char(code_point) คืนค่าตัวอักษรจาก Code Point

ตัวอย่างผลลัพธ์

Name (Input)First CharUnicode Code PointHexแสดงใน ListView
SairamS83U+0053Sairam → U+0053 (83)
JohnJ74U+004AJohn → U+004A (74)
日本語日26085U+65E5日本語 → U+65E5 (26085)
😀😀128512U+1F600😀 → U+1F600 (128512)
สวัสดีส3629U+0E2Aสวัสดี → U+0E2A (3629)

ฟังก์ชันเกี่ยวข้องใน SQLite

1. char() - ทำงานกลับกันกับ unicode()

SELECT char(65);        -- 'A'
SELECT char(0x0E2A);    -- 'ส' (Thai character)
SELECT char(128512);    -- '😀' (Emoji - ต้องการ SQLite compiled with UTF-16 support)

2. ใช้ร่วมกับ substr() สำหรับตัวอักษรที่ไม่ใช่ตัวแรก

-- Code point ของตัวอักษรที่ 2
SELECT unicode(substr(name, 2, 1)) FROM table;

-- Code point ของทุกตัวอักษร (ต้องใช้ Recursive CTE หรือ Application Layer)

3. ตรวจสอบช่วง Unicode (Unicode Blocks)

-- ตรวจสอบว่าตัวแรกเป็นอักษรไทยหรือไม่ (Thai: U+0E00–U+0E7F)
SELECT CASE 
    WHEN unicode(name) BETWEEN 0x0E00 AND 0x0E7F THEN 'Thai'
    WHEN unicode(name) BETWEEN 0x0041 AND 0x005A THEN 'Latin Upper'
    WHEN unicode(name) BETWEEN 0x0061 AND 0x007A THEN 'Latin Lower'
    ELSE 'Other'
END as script FROM table;

การใช้งานใน Java/Kotlin

// Java: ได้ Code Point ของ char
String str = "สวัสดี";
int cp = str.codePointAt(0); // 3629 (U+0E2A)

// ทุก Code Points ใน String
str.codePoints().forEach(cp -> 
    System.out.printf("U+%04X %s%n", cp, Character.getName(cp)));

// Kotlin
val cp = str.codePointAt(0)
str.codePoints.forEach { println(it.toString(16).uppercase().padStart(4, '0')) }

กรณีการใช้งานจริง

  • Data Validation: ตรวจสอบว่าข้อมูลอยู่ใน Unicode Block ที่คาดหวัง (Thai, Latin, CJK, Emoji)
  • Sorting/Collation: เรียงตาม Code Point (Binary Sort) แทน Locale-aware Collation
  • Search/Filter: ค้นหาตัวอักษรพิเศษ, Control Characters, Non-printable
  • Encoding Debug: ตรวจสอบว่า Character Encoding ถูกต้องหรือไม่
  • Security: ตรวจจับ Homograph Attacks (ตัวอักษรคล้ายกันแต่ Code Point ต่างกัน)

ข้อควรระวัง

  • ตัวอักษรแรกเท่านั้น: unicode() ดูแค่ตัวแรก ต้องใช้ substr() สำหรับตัวอื่น
  • Surrogate Pairs: Emoji/Supplementary Characters ใช้ 2 UTF-16 Code Units แต่ unicode() คืน Code Point เดียว (ถูกต้อง)
  • NULL/Empty: คืน NULL - ต้อง Handle ใน Application
  • Performance: เรียก unicode() ทุก Row อาจช้า - ใช้ Index/Computed Column หาก Query บ่อย

Unicode Blocks ที่พบบ่อย

BlockRange (Hex)ตัวอย่าง
Basic LatinU+0000–U+007FA, z, 0, @
ThaiU+0E00–U+0E7Fก, ข, ำ, ฯ
CJK Unified IdeographsU+4E00–U+9FFF中, 文, 日
EmoticonsU+1F600–U+1F64F😀, 😂, 😭
Misc SymbolsU+2600–U+26FF☀, ☂, ♠, ♥