8

động cơ biểu hiện thường xuyên có một khái niệm về "zero chiều rộng" trận đấu, một số trong số đó là hữu ích cho việc tìm kiếm cạnh của chữ:biểu hiện thường xuyên để phù hợp với ranh giới giữa các kịch bản Unicode khác nhau

  • \b - hiện diện trong hầu hết các động cơ để phù hợp với bất kỳ ranh giới nào giữa các ký tự từ và ký tự không phải từ
  • \< and \> - present in Vim chỉ để đối sánh ranh giới ở đầu một từ và ở cuối từ, tương ứng.

Một khái niệm mới hơn trong một số công cụ biểu thức chính quy là các lớp Unicode. Một trong những lớp là kịch bản, có thể phân biệt tiếng Latin, Hy Lạp, Cyrillic, vv Những ví dụ là tất cả tương đương và phù hợp với bất kỳ ký tự của hệ thống chữ viết Hy Lạp:

  • \p{greek}
  • \p{script=greek}
  • \p{script:greek}
  • [:script=greek:]
  • [:script:greek:]

Nhưng cho đến nay trong đọc của tôi thông qua các nguồn về biểu thức thông thường và Unicode tôi đã không thể xác định nếu có bất kỳ cách tiêu chuẩn hoặc không chuẩn để đạt được một trận đấu không chiều rộng, nơi một kịch bản kết thúc và khác bắt đầu.

Trong chuỗi παν語 sẽ có một trận đấu giữa ν nhân vật, cũng giống như \b\< sẽ phù hợp ngay trước khi nhân vật π.

Bây giờ cho ví dụ này tôi có thể hack một cái gì đó cùng nhau dựa trên tìm kiếm \p{Greek} theo sau là \p{Han} và thậm chí tôi có thể hack một thứ gì đó cùng nhau dựa trên tất cả các kết hợp có thể có của hai tên tập lệnh Unicode.

Nhưng đây không phải là giải pháp xác định vì các tập lệnh mới vẫn đang được thêm vào Unicode với mỗi bản phát hành. Có cách nào để chứng minh điều này trong tương lai không? Hoặc có đề xuất thêm nó không?

+2

Đóng nhưng không chính xác giống nhau: http://stackoverflow.com/questions/14942652/how-to-emulate-word-boundary-when-using-unicode-character-properties/14942906#14942906 Câu trả lời của tôi là ranh giới cho một lớp nhân vật duy nhất (và điều này áp dụng cho bất kỳ lớp nhân vật nào). Câu hỏi của bạn là về ranh giới giữa bất kỳ ngôn ngữ nào. – nhahtdh

+0

@nhahtdh: Cảm ơn. Tôi ngạc nhiên là tôi không tìm thấy câu hỏi của bạn trong tìm kiếm của tôi. – hippietrail

+1

Tôi nghĩ rằng tất cả mọi người nên đọc phần 2 của điều này: http://www.unicode.org/reports/tr24/ – nhahtdh

Trả lời

3

EDIT: Tôi chỉ nhận thấy bạn không thực sự rõ mô hình khớp ngôn ngữ mà bạn đang sử dụng. Vâng, tôi hy vọng một giải pháp Perl sẽ làm việc cho bạn, vì các cơ chế cần thiết có thể sẽ thực sự khó khăn trong bất kỳ ngôn ngữ nào khác. Ngoài ra, nếu bạn đang làm mẫu phù hợp với Unicode, Perl thực sự là lựa chọn tốt nhất có sẵn cho loại công việc cụ thể đó.


Khi biến $rx dưới đây được thiết lập để mô hình thích hợp, đoạn này ít mã Perl:

my $data = "foo1 and Πππ 語語語 done"; 

while ($data =~ /($rx)/g) { 
    print "Got string: '$1'\n"; 
} 

Tạo đầu ra này:

Got string: 'foo1 and ' 
Got string: 'Πππ ' 
Got string: '語語語 ' 
Got string: 'done' 

Nghĩa là, nó kéo ra một chuỗi Latin, một chuỗi tiếng Hy Lạp, một chuỗi Hán, và một chuỗi tiếng Latin khác.Điều này là khá darned đóng cửa với những gì tôi nghĩ rằng bạn thực sự cần.

Lý do tôi không đăng bài này hôm qua là tôi đã nhận được các vùng lõi kỳ lạ. Bây giờ tôi biết tại sao.

Giải pháp của tôi sử dụng các biến từ vựng bên trong cấu trúc (??{...}). Hóa ra rằng điều đó không ổn định trước v5.17.1, và chỉ được làm việc tốt nhất một cách tình cờ. Nó không thành công trên v5.17.0, nhưng thành công trên v5.18.0 RC0 và RC2. Vì vậy, tôi đã thêm một số use v5.17.1 để đảm bảo rằng bạn đang điều hành đủ gần đây để tin tưởng với phương pháp này.

Trước tiên, tôi quyết định rằng bạn không thực sự muốn chạy một loại tập lệnh giống nhau; bạn muốn chạy một loại tập lệnh giống nhau cộng với Thông thường và được kế thừa. Nếu không, bạn sẽ bị rối tung bởi dấu chấm câu và khoảng trắng và chữ số cho Common, và bằng cách kết hợp các ký tự cho Inherited. Tôi thực sự không nghĩ rằng bạn muốn những người đó làm gián đoạn hoạt động của bạn "tất cả cùng một kịch bản", nhưng nếu bạn làm thế, thật dễ dàng để ngừng xem xét những điều đó.

Vì vậy, điều chúng tôi làm là chú ý đến ký tự đầu tiên có loại tập lệnh khác với Thông thường hoặc Được kế thừa. Hơn thế nữa, chúng tôi trích xuất từ ​​đó loại kịch bản thực sự là gì và sử dụng thông tin này để tạo mẫu mới là bất kỳ số ký tự nào có loại tập lệnh là Phổ biến, Kế thừa hoặc bất kỳ loại tập lệnh nào mà chúng tôi vừa tìm và lưu. Sau đó, chúng tôi đánh giá mô hình mới và tiếp tục.

Xin chào, tôi cho biết nó đã là lông, phải không?

Trong chương trình tôi sắp hiển thị, tôi đã để lại trong một số báo cáo gỡ lỗi đã nhận xét chỉ hiển thị những gì nó đang thực hiện. Nếu bạn bỏ ghi chú họ, bạn nhận được kết quả này cho thời gian qua, mà sẽ giúp hiểu được cách tiếp cận:

DEBUG: Got peekahead character f, U+0066 
DEBUG: Scriptname is Latin 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Latin}]*} 
Got string: 'foo1 and ' 
DEBUG: Got peekahead character Π, U+03a0 
DEBUG: Scriptname is Greek 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Greek}]*} 
Got string: 'Πππ ' 
DEBUG: Got peekahead character 語, U+8a9e 
DEBUG: Scriptname is Han 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Han}]*} 
Got string: '語語語 ' 
DEBUG: Got peekahead character d, U+0064 
DEBUG: Scriptname is Latin 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Latin}]*} 
Got string: 'done' 

Và đây cuối cùng là thỏa thuận lông lớn:

use v5.17.1; 
use strict; 
use warnings; 
use warnings FATAL => "utf8"; 
use open qw(:std :utf8); 
use utf8; 

use Unicode::UCD qw(charscript); 

# regex to match a string that's all of the 
# same Script=XXX type 
# 
my $rx = qr{ 
    (?= 
     [\p{Script=Common}\p{Script=Inherited}] * 
     (?<CAPTURE> 
      [^\p{Script=Common}\p{Script=Inherited}] 
     ) 
    ) 
    (??{ 
     my $capture = $+{CAPTURE}; 
    #####printf "DEBUG: Got peekahead character %s, U+%04x\n", $capture, ord $capture; 
     my $scriptname = charscript(ord $capture); 
    #####print "DEBUG: Scriptname is $scriptname\n"; 
     my $run = q([\p{Script=Common}\p{Script=Inherited}\p{Script=) 
       . $scriptname 
       . q(}]*); 
    #####print "DEBUG: string to re-interpolate as regex is q{$run}\n"; 
     $run; 
    }) 
}x; 


my $data = "foo1 and Πππ 語語語 done"; 

$| = 1; 

while ($data =~ /($rx)/g) { 
    print "Got string: '$1'\n"; 
} 

Yeah, có Oughta được Một cách tốt hơn. Tôi không nghĩ là có.

Vì vậy, bây giờ, hãy tận hưởng.

+0

Ồ tôi đặc biệt không chỉ định phương ngữ regex, thay vào đó tôi hỏi về "tiêu chuẩn", "không chuẩn" và "được đề xuất". Tôi thực sự chơi với XRegExp và đọc qua UTS # 18 và regular-expressions.info nhưng tôi quen với việc triển khai của Perl và Vim. Tôi đoán tôi muốn biết những gì tôi có thể làm, ngay cả khi các phương ngữ cụ thể chưa thực hiện nó. Đối với cách giải quyết, tôi giả sử JavaScript hoặc thậm chí là một phần mở rộng cho XRegExp sẽ là tốt nhất. (Tôi đang viết điều này trước khi đọc nội dung câu trả lời của bạn bằng cách này ...) – hippietrail

+1

@hippietrail UTS # 18 sẽ không đề cập đến điều này cho đến khi ít nhất là Cấp 3 và chưa ai thực hiện điều đó. Vì vậy, chúng tôi làm với những gì chúng tôi có thể trong khi đó. Gần đây tôi chưa thực sự nhìn nó, vì vậy không biết điều này có thể thực hiện được ở Cấp độ 3 hay không. – tchrist

+0

Bên cạnh chính bản thân bạn, ai đang tích cực đẩy mạnh phát triển Unicode regex trong những ngày này? Tôi biết Perl đã hỗ trợ Unicode tốt nhất và đó là một trong những lý do chính nó là ngôn ngữ chính của tôi trong nhiều năm, nhưng bây giờ tôi đã chuyển sang các lý do khác cho một ngôn ngữ với một số hỗ trợ Unicode tồi tệ nhất. Tôi chắc chắn có thể đến với một splitter chuỗi regex không nhưng nó có vẻ như một tính năng rõ ràng để bao gồm trong một động cơ regex. Có lẽ tôi nên gửi một số đề xuất? – hippietrail

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