File Coverage

blib/lib/Text/Shirasu.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Text::Shirasu;
2              
3 5     5   106504 use strict;
  5         7  
  5         139  
4 5     5   19 use warnings;
  5         9  
  5         124  
5 5     5   564 use utf8;
  5         21  
  5         27  
6 5     5   114 use Exporter 'import';
  5         8  
  5         123  
7 5     5   4025 use Text::MeCab;
  0            
  0            
8             use Carp 'croak';
9             use Text::Shirasu::Node;
10             use Lingua::JA::NormalizeText;
11             use Encode qw/encode_utf8 decode_utf8/;
12              
13             our $VERSION = "0.0.2";
14             our @EXPORT_OK = (@Lingua::JA::NormalizeText::EXPORT_OK, qw/normalize_hyphen normalize_symbols/);
15              
16             *nfkc = \&Lingua::JA::NormalizeText::nfkc;
17             *nfkd = \&Lingua::JA::NormalizeText::nfkd;
18             *nfc = \&Lingua::JA::NormalizeText::nfc;
19             *nfd = \&Lingua::JA::NormalizeText::nfd;
20             *decode_entities = \&Lingua::JA::NormalizeText::decode_entities;
21             *alnum_z2h = \&Lingua::JA::NormalizeText::alnum_z2h;
22             *alnum_h2z = \&Lingua::JA::NormalizeText::alnum_h2z;
23             *space_z2h = \&Lingua::JA::NormalizeText::space_z2h;
24             *space_h2z = \&Lingua::JA::NormalizeText::space_h2z;
25             *katakana_z2h = \&Lingua::JA::NormalizeText::katakana_z2h;
26             *katakana_h2z = \&Lingua::JA::NormalizeText::katakana_h2z;
27             *katakana2hiragana = \&Lingua::JA::NormalizeText::katakana2hiragana;
28             *hiragana2katakana = \&Lingua::JA::NormalizeText::hiragana2katakana;
29             *dakuon_normalize = \&Lingua::JA::NormalizeText::dakuon_normalize;
30             *handakuon_normalize = \&Lingua::JA::NormalizeText::handakuon_normalize;
31             *all_dakuon_normalize = \&Lingua::JA::NormalizeText::all_dakuon_normalize;
32             *square2katakana = \&Lingua::JA::NormalizeText::square2katakana;
33             *circled2kana = \&Lingua::JA::NormalizeText::circled2kana;
34             *circled2kanji = \&Lingua::JA::NormalizeText::circled2kanji;
35             *strip_html = \&Lingua::JA::NormalizeText::strip_html;
36             *wave2tilde = \&Lingua::JA::NormalizeText::wave2long;
37             *tilde2wave = \&Lingua::JA::NormalizeText::tilde2wave;
38             *wavetilde2long = \&Lingua::JA::NormalizeText::wavetilde2long;
39             *wave2long = \&Lingua::JA::NormalizeText::wave2long;
40             *tilde2long = \&Lingua::JA::NormalizeText::tilde2long;
41             *fullminus2long = \&Lingua::JA::NormalizeText::fullminus2long;
42             *dashes2long = \&Lingua::JA::NormalizeText::dashes2long;
43             *drawing_lines2long = \&Lingua::JA::NormalizeText::drawing_lines2long;
44             *unify_long_repeats = \&Lingua::JA::NormalizeText::unify_long_repeats;
45             *unify_long_spaces = \&Lingua::JA::NormalizeText::unify_long_spaces;
46             *unify_whitespaces = \&Lingua::JA::NormalizeText::unify_whitespaces;
47             *trim = \&Lingua::JA::NormalizeText::trim;
48             *ltrim = \&Lingua::JA::NormalizeText::ltrim;
49             *rtrim = \&Lingua::JA::NormalizeText::rtrim;
50             *nl2space = \&Lingua::JA::NormalizeText::nl2space;
51             *unify_nl = \&Lingua::JA::NormalizeText::unify_nl;
52             *tab2space = \&Lingua::JA::NormalizeText::tab2space;
53             *old2new_kana = \&Lingua::JA::NormalizeText::old2new_kana;
54             *remove_controls = \&Lingua::JA::NormalizeText::remove_controls;
55             *remove_spaces = \&Lingua::JA::NormalizeText::remove_spaces;
56             *remove_DFC = \&Lingua::JA::NormalizeText::remove_DFC;
57             *old2new_kanji = \&Lingua::JA::NormalizeText::old2new_kanji;
58             *decompose_parenthesized_kanji
59             = \&Lingua::JA::NormalizeText::decompose_parenthesized_kanji;
60              
61             =encoding utf-8
62              
63             =head1 NAME
64              
65             Text::Shirasu - Text::MeCab wrapped for natural language processing
66              
67             =head1 SYNOPSIS
68              
69             use utf8;
70             use feature ':5.10';
71             use Text::Shirasu;
72             my $ts = Text::Shirasu->new; # this parameter same as Text::MeCab
73             my $normalize = $ts->normalize("昨日の晩御飯は「鮭のふりかけ」と「味噌汁」だけでした。");
74             $ts->parse($normalize);
75              
76             for my $node (@{ $ts->nodes }) {
77             say $node->surface;
78             }
79              
80             say $ts->join_surface;
81              
82             my $filter = $ts->filter(type => [qw/名詞 助動詞/], 記号 => [qw/括弧開 括弧閉/]);
83             say $filter->join_surface;
84              
85             =head1 DESCRIPTION
86              
87             Text::Shirasu is wrapped L.
88             This module is easy to normalize text and filter part of speech.
89              
90             =cut
91              
92             sub new {
93             my $class = shift;
94             my %args = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
95             return bless {
96             mecab => Text::MeCab->new(%args),
97             nodes => +[],
98             normalize => +[qw/
99             nfkc
100             nfkd
101             nfc
102             nfd
103             alnum_z2h
104             space_z2h
105             katakana_h2z
106             decode_entities
107             unify_nl
108             unify_whitespaces
109             unify_long_spaces
110             trim
111             old2new_kana
112             old2new_kanji
113             tab2space
114             all_dakuon_normalize
115             square2katakana
116             circled2kana
117             circled2kanji
118             decompose_parenthesized_kanji
119             /, \&normalize_hyphen, \&normalize_symbols
120             ],
121             } => $class;
122             }
123              
124             =head1 METHODS
125             =cut
126              
127             =head2 parse
128              
129             This method wraps the parse method of Text::MeCab.
130             The analysis result is saved as Text::Shirasu::Node instance in the Text::Shirasu instance. So, It will return Text::Shirasu instance.
131              
132             $ts->parse("このおにぎりは「母」が握ってくれたものです。");
133              
134             =cut
135              
136             sub parse {
137             my $self = shift;
138             my $sentence = $_[0];
139              
140             croak "Sentence has not been inputted" unless $sentence;
141              
142             my $mt = $self->{mecab};
143              
144             # initialize
145             $self->{nodes} = [];
146              
147             for (my $node = $mt->parse($sentence); $node && $node->surface; $node = $node->next) {
148             push @{ $self->{nodes} }, bless {
149             id => $node->id,
150             surface => $node->surface,
151             feature => [ split /,/, $node->feature ],
152             length => $node->length,
153             rlength => $node->rlength,
154             rcattr => $node->rcattr,
155             lcattr => $node->lcattr,
156             stat => $node->stat,
157             isbest => $node->isbest,
158             alpha => $node->alpha,
159             beta => $node->beta,
160             prob => $node->prob,
161             wcost => $node->wcost,
162             cost => $node->cost,
163             }, 'Text::Shirasu::Node';
164             }
165              
166             return $self;
167             }
168              
169             =head2 normalize
170              
171             It will normalize text using L.
172              
173             $ts->normalize("あ━ ”(*)” を〰〰 ’+1’")
174             $ts->normalize("テキスト〰〰", qw/nfkc, alnum_z2h/, \&your_create_routine)
175              
176             It accepts a string as the first argument, and receives the Lingua::JA::NormalizeText options and subroutines after the second argument.
177             If you do not specify a subroutine to be used in normalization, use the following Lingua::JA::NormalizeText options and subroutines by default.
178              
179             Please read the documentation of L for details on how each Lingua::JA::NormalizeText option works.
180              
181             Lingua::JA::NormalizeText options
182              
183             C
184              
185             Subroutines
186              
187             C
188              
189             =cut
190              
191             sub normalize {
192             my $self = shift;
193             my $text = shift;
194             my $normalizer = Lingua::JA::NormalizeText->new(@_ ? @_ : @{ $self->{normalize} });
195             $normalizer->normalize(utf8::is_utf8($text) ? $text : decode_utf8($text));
196             }
197              
198             =head2 filter
199              
200             Please use after parse method execution.
201             Filter the surface based on the features stored in the Text::Shirasu instance.
202             Passing subtype to value with part of speech name as key allows you to more filter the string.
203              
204             $ts->filter(type => [qw/名詞/]);
205             $ts->filter(type => [qw/名詞 記号/], 記号 => [qw/括弧開 括弧閉/]);
206              
207             =cut
208              
209             sub filter {
210             my $self = shift;
211             my %params = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
212              
213             # and search filter
214             my @type = @{ delete $params{type} }
215             or croak 'Query has not been inputted: "type"';
216              
217             # create parameter as /名詞|動詞/ or /名詞/
218             my $query = join '|', @type;
219             $query = encode_utf8($query) if utf8::is_utf8 $query;
220              
221             $self->{nodes} = [
222             grep {
223             $_->{feature}->[0] =~ /($query)/
224             and _sub_query( $_->{feature}->[1], $params{$1} )
225             } @{ $self->{nodes} }
226             ];
227              
228             return $self;
229             }
230              
231             =head2 join_surface
232              
233             Returns a string that combined the surfaces stored in the instance.
234            
235             $ts->join_surface
236              
237             =cut
238              
239             sub join_surface {
240             my $self = shift;
241             croak "Does not exist parsed nodes" unless exists $self->{nodes};
242             return join '', map { $_->{surface} } @{ $self->{nodes} };
243             }
244              
245             =head2 nodes
246              
247             Return the array reference of the Text::Shirasu::Node instance.
248            
249             $ts->nodes
250              
251             =cut
252              
253             sub nodes { $_[0]->{nodes} }
254              
255             =head2 mecab
256              
257             Return the Text::MeCab instance.
258            
259             $ts->mecab
260              
261             =cut
262              
263             sub mecab { $_[0]->{mecab} }
264              
265             # private
266             sub _sub_query {
267             my ( $subtype, $query ) = @_;
268              
269             return 1 unless ref $query eq 'ARRAY';
270              
271             my $judge = join '|', map { encode_utf8($_) } @$query;
272              
273             return $subtype =~ /$judge/;
274             }
275              
276             1;
277              
278             =head1 SUBROUTINES
279              
280             These subroutines perform the following substitution.
281              
282             =head2 normalize_hyphen
283              
284             s/[˗֊‐‑‒–⁃⁻₋−]/-/g;
285             s/[﹣-ー—―─━ー]/ー/g;
286             s/[~∼∾〜〰~]//g;
287             s/ー+/ー/g;
288              
289             =head2 normalize_symbols
290              
291             tr/。、・「」/。、・「」/;
292              
293             =cut
294              
295             sub normalize_hyphen {
296             local $_ = shift;
297             return undef unless defined $_;
298             s/[˗֊‐‑‒–⁃⁻₋−]/-/g;
299             s/[﹣-ー—―─━ー]/ー/g;
300             s/[~∼∾〜〰~]//g;
301             s/ー+/ー/g;
302             $_;
303             }
304              
305             sub normalize_symbols {
306             local $_ = shift;
307             return undef unless defined $_;
308             tr/。、・「」/。、・「」/;
309             $_;
310             }
311              
312             =head1 LICENSE
313              
314             Copyright (C) Kei Kamikawa(Code-Hex).
315              
316             This library is free software; you can redistribute it and/or modify
317             it under the same terms as Perl itself.
318              
319             =head1 AUTHOR
320              
321             Kei Kamikawa Ex00.x7f@gmail.comE
322              
323             =cut