2012-05-24 39 views
6

Tôi cần chuẩn hóa một chuỗi như "quée" và tôi dường như không thể chuyển đổi các ký tự ASCII mở rộng như é, á, í, v.v ... thành các phiên bản tiếng Roman/tiếng Anh. Tôi đã thử một số phương pháp khác nhau nhưng không có gì hoạt động cho đến nay. Có một số lượng hợp lý của tài liệu về chủ đề chung này nhưng tôi dường như không thể tìm thấy một câu trả lời làm việc cho vấn đề này.Bình thường hóa các ký tự ASCII

Dưới đây là mã của tôi:

#transliteration solution (works great with standard chars but doesn't find the 
#special ones) - I've tried looking for both \x{130} and é with the same result. 
$mystring =~ tr/\\x{130}/e/; 

#converting into array, then iterating through and replacing the specific char 
#(same result as the above solution) 
my @breakdown = split("",$mystring); 

foreach (@breakdown) { 
    if ($_ eq "\x{130}") { 
     $_ = "e"; 
     print "\nArray Output: @breakdown\n"; 
    } 
    $lowercase = join("",@breakdown); 
} 

Trả lời

9

1) article này nên cung cấp một cách khá tốt (nếu phức tạp).

Nó cung cấp giải pháp để chuyển đổi tất cả các ký tự Unicode có dấu vào ký tự cơ bản + dấu trọng âm; khi đã xong, bạn có thể chỉ cần xóa riêng các ký tự dấu trọng âm.


2) Một lựa chọn khác là CPAN: Text::Unaccent::PurePerl (Một cải thiện tinh khiết Perl phiên bản của Text::Unaccent)


3) Ngoài ra, this SO answer đề xuất Text::Unidecode:

$ perl -Mutf8 -MText::Unidecode -E 'say unidecode("été")' 
    ete 
+0

Giải pháp tuyệt vời, nó hoạt động tuyệt vời !!! Cảm ơn bạn! –

7

Lý do mã ban đầu của bạn không hoạt động là t mũ \x{130} không phải là é. Đó là LATIN CAPITAL LETTER I WITH DOT ABOVE (U+0130 or İ). Bạn có nghĩa là \x{E9} hoặc chỉ \xE9 (dấu ngoặc nhọn là tùy chọn cho số có hai chữ số), LATIN SMALL LETTER E WITH ACUTE (U+00E9).

Ngoài ra, bạn có thêm dấu gạch chéo ngược trong số tr; nó sẽ trông giống như tr/\xE9/e/.

Với những thay đổi đó, mã của bạn sẽ hoạt động, mặc dù tôi vẫn khuyên bạn nên sử dụng một trong các mô-đun trên CPAN cho loại điều này. Tôi thích Text::Unidecode cho điều này bản thân mình, vì nó xử lý nhiều hơn chỉ là ký tự có dấu.

+1

Cảm ơn sự giúp đỡ của bạn! Tôi đã thực hiện các thay đổi của bạn và nó hoạt động ngay bây giờ. Tôi đang thực sự sử dụng một mô-đun trong phiên bản được phân phối vì nó có vẻ là cách thanh lịch nhất, mặc dù thật tốt khi biết tôi không ở quá xa. –

3

Sau khi làm việc và làm việc lại, đây là những gì tôi có bây giờ. Nó làm mọi thứ tôi muốn, ngoại trừ tôi muốn giữ khoảng trống ở giữa các chuỗi đầu vào để phân biệt giữa các từ.

open FILE, "funnywords.txt"; 

# Iterate through funnywords.txt 
while (<FILE>) { 
    chomp; 

    # Show initial text from file 
    print "In: '$_' -> "; 

    my $inputString = $_; 

    # $inputString is scoped within a for each loop which dissects 
    # unicode characters (example: "é" splits into "e" and "´") 
    # and throws away accent marks. Also replaces all 
    # non-alphanumeric characters with spaces and removes 
    # extraneous periods and spaces. 
    for ($inputString) { 
     $inputString = NFD($inputString); # decompose/dissect 
     s/^\s//; s/\s$//;     # strip begin/end spaces 
     s/\pM//g;       # strip odd pieces 
     s/\W+//g;       # strip non-word chars 
    } 

    # Convert to lowercase 
    my $outputString = "\L$inputString"; 

    # Output final result 
    print "$outputString\n"; 
} 

Không hoàn toàn chắc chắn lý do tại sao nó được tô màu một số các regex và ý kiến ​​đỏ ...

Dưới đây là một vài ví dụ về dòng từ "funnywords.txt":

quée

22.

? ÉÉíóñúÑ¿¡

[.this? ]

đấy nhé, Alli

2

Đối với câu hỏi thứ hai của bạn về việc loại bỏ bất kỳ biểu tượng còn lại nhưng giữ chữ và số thay đổi regex cuối cùng của bạn từ s/\W+//g để s/[^a-zA-Z0-9 ]+//g. Vì bạn đã chuẩn hóa phần còn lại của đầu vào, sử dụng regex đó sẽ xóa mọi thứ không phải là a-z, A-Z, 0-9 hoặc khoảng trắng.Sử dụng ký tự [] và^ngay từ đầu sẽ cho biết bạn muốn tìm mọi thứ KHÔNG ở phần còn lại của dấu ngoặc.

Các vấn đề liên quan