Modify data-validation script and dictionary-validation script to disallow exotic...
authorJan "yenda" Trmal <jtrmal@gmail.com>
Thu, 28 Sep 2017 04:10:42 +0000 (00:10 -0400)
committerGitHub <noreply@github.com>
Thu, 28 Sep 2017 04:10:42 +0000 (00:10 -0400)
* validate_lang checks for incompatible UTF-8 whitespaces

* adding validate_dict_dir as well

* include utf-8 whitespaces validation for data/<name>/text files

* fix perl syntax error

egs/wsj/s5/utils/validate_data_dir.sh
egs/wsj/s5/utils/validate_dict_dir.pl
egs/wsj/s5/utils/validate_lang.pl
egs/wsj/s5/utils/validate_text.pl [new file with mode: 0755]

index 92ba8f8b63082f9e84a6c25629e7ca7fed5c1643..6b82b433355e6e24962bff55fa5a02f14f9fae39 100755 (executable)
@@ -108,6 +108,7 @@ fi
 
 num_utts=`cat $tmpdir/utts | wc -l`
 if [ -f $data/text ]; then
+  utils/validate_text.pl $data/text || exit 1;
   check_sorted_and_uniq $data/text
   text_len=`cat $data/text | wc -l`
   illegal_sym_list="<s> </s> #0"
index a5c9ff8da21b519bc3aac69a875f6f88d6095304..25e45da97e519ca08369e023c76fe9d460d70d0f 100755 (executable)
@@ -1,11 +1,95 @@
 #!/usr/bin/env perl
 
 # Apache 2.0.
-# Guoguo Chen (guoguo@jhu.edu)
-# Daniel Povey (dpovey@gmail.com)
+# Copyright  2012 Guoguo Chen
+#            2015 Daniel Povey
+#            2017 Johns Hopkins University (Jan "Yenda" Trmal <jtrmal@gmail.com>)
 #
 # Validation script for data/local/dict
 
+# this function reads the opened file (supplied as a first
+# parameter) into an array of lines. For each
+# line, it tests whether it's a valid utf-8 compatible
+# line. If all lines are valid utf-8, it returns the lines
+# decoded as utf-8, otherwise it assumes the file's encoding
+# is one of those 1-byte encodings, such as ISO-8859-x
+# or Windows CP-X.
+# Please recall we do not really care about
+# the actually encoding, we just need to
+# make sure the length of the (decoded) string
+# is correct (to make the output formatting looking right).
+sub get_utf8_or_bytestream {
+  use Encode qw(decode encode);
+  my $is_utf_compatible = 1;
+  my @unicode_lines;
+  my @raw_lines;
+  my $raw_text;
+  my $lineno = 0;
+  my $file = shift;
+
+  while (<$file>) {
+    $raw_text = $_;
+    last unless $raw_text;
+    if ($is_utf_compatible) {
+      my $decoded_text = eval { decode("UTF-8", $raw_text, Encode::FB_CROAK) } ;
+      $is_utf_compatible = $is_utf_compatible && defined($decoded_text);
+      push @unicode_lines, $decoded_text;
+    } else {
+      #print STDERR "WARNING: the line $raw_text cannot be interpreted as UTF-8: $decoded_text\n";
+      ;
+    }
+    push @raw_lines, $raw_text;
+    $lineno += 1;
+  }
+
+  if (!$is_utf_compatible) {
+    return (0, @raw_lines);
+  } else {
+    return (1, @unicode_lines);
+  }
+}
+
+# check if the given unicode string contain unicode whitespaces
+# other than the usual four: TAB, LF, CR and SPACE
+sub validate_utf8_whitespaces {
+  my $unicode_lines = shift;
+  use feature 'unicode_strings';
+  for (my $i = 0; $i < scalar @{$unicode_lines}; $i++) {
+    my $current_line = $unicode_lines->[$i];
+    # we replace TAB, LF, CR, and SPACE
+    # this is to simplify the test
+    $current_line =~ s/[\x{0009}\x{000a}\x{000d}\x{0020}]/./g;
+    if ($current_line =~/\s/) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+# checks if the text in the file (supplied as the argument) is utf-8 compatible
+# if yes, checks if it contains only allowed whitespaces. If no, then does not
+# do anything. The function seeks to the original position in the file after
+# reading the text.
+sub check_allowed_whitespace {
+  my $file = shift;
+  my $pos = tell($file);
+  (my $is_utf, my @lines) = get_utf8_or_bytestream($file);
+  seek($file, $pos, SEEK_SET);
+  if ($is_utf) {
+    my $has_invalid_whitespaces = validate_utf8_whitespaces(\@lines);
+    print "--> text seems to be UTF-8 or ASCII, checking whitespaces\n";
+    if ($has_invalid_whitespaces) {
+      print "--> ERROR: the text containes disallowed UTF-8 whitespace character(s)\n";
+      return 0;
+    } else {
+      print "--> text contains only allowed whitespaces\n";
+    }
+  } else {
+    print "--> text doesn't seem to be UTF-8 or ASCII, won't check whitespaces\n";
+  }
+  return 1;
+}
+
 
 if(@ARGV != 1) {
   die "Usage: validate_dict_dir.pl <dict-dir>\n" .
@@ -29,6 +113,7 @@ $idx = 1;
 $crlf = 1;
 
 print "--> reading $dict/silence_phones.txt\n";
+check_allowed_whitespace(\*S) || set_to_fail();
 while(<S>) {
   if (! s/\n$//) {
     print "--> ERROR: last line '$_' of $dict/silence_phones.txt does not end in newline.\n";
@@ -73,6 +158,7 @@ $idx = 1;
 $success = 1;
 $crlf = 1;
 print "--> reading $dict/optional_silence.txt\n";
+check_allowed_whitespace(\*OS) or exit 1;
 while(<OS>) {
   chomp;
   my @col = split(" ", $_);
@@ -101,6 +187,7 @@ $idx = 1;
 $success = 1;
 $crlf = 1;
 print "--> reading $dict/nonsilence_phones.txt\n";
+check_allowed_whitespace(\*NS) or set_to_fail();
 while(<NS>) {
   if ($crlf == 1 && m/\r/) {
     print "--> ERROR: $dict/nonsilence_phones.txt contains Carriage Return (^M) characters.\n";
@@ -166,6 +253,7 @@ sub check_lexicon {
   my %seen_line = {};
   $idx = 1; $success = 1; $crlf = 1;
   print "--> reading $lex\n";
+  check_allowed_whitespace(\*L) or set_to_fail();
   while (<L>) {
     if ($crlf == 1 && m/\r/) {
       print "--> ERROR: $lex contains Carriage Return (^M) characters.\n";
@@ -333,6 +421,7 @@ if (-s "$dict/extra_questions.txt") {
   $success = 1;
   $crlf = 1;
   print "--> reading $dict/extra_questions.txt\n";
+  check_allowed_whitespace(\*EX) or set_to_fail();
   while(<EX>) {
     if ($crlf == 1 && m/\r/) {
       print "--> ERROR: $dict/extra_questions.txt contains Carriage Return (^M) characters.\n";
index 389fe6d344d61695beb09c29108d1fbd62be0831..7e95545b2840d5f61c88cb5795007149f59d53dd 100755 (executable)
@@ -3,9 +3,92 @@
 # Apache 2.0.
 # Copyright  2012   Guoguo Chen
 #            2014   Neil Nelson
+#            2017   Johns Hopkins University (Jan "Yenda" Trmal <jtrmal@gmail.com>)
 #
 # Validation script for data/lang
 
+# this function reads the opened file (supplied as a first
+# parameter) into an array of lines. For each
+# line, it tests whether it's a valid utf-8 compatible
+# line. If all lines are valid utf-8, it returns the lines
+# decoded as utf-8, otherwise it assumes the file's encoding
+# is one of those 1-byte encodings, such as ISO-8859-x
+# or Windows CP-X.
+# Please recall we do not really care about
+# the actually encoding, we just need to
+# make sure the length of the (decoded) string
+# is correct (to make the output formatting looking right).
+sub get_utf8_or_bytestream {
+  use Encode qw(decode encode);
+  my $is_utf_compatible = 1;
+  my @unicode_lines;
+  my @raw_lines;
+  my $raw_text;
+  my $lineno = 0;
+  my $file = shift;
+
+  while (<$file>) {
+    $raw_text = $_;
+    last unless $raw_text;
+    if ($is_utf_compatible) {
+      my $decoded_text = eval { decode("UTF-8", $raw_text, Encode::FB_CROAK) } ;
+      $is_utf_compatible = $is_utf_compatible && defined($decoded_text);
+      push @unicode_lines, $decoded_text;
+    } else {
+      #print STDERR "WARNING: the line $raw_text cannot be interpreted as UTF-8: $decoded_text\n";
+      ;
+    }
+    push @raw_lines, $raw_text;
+    $lineno += 1;
+  }
+
+  if (!$is_utf_compatible) {
+    return (0, @raw_lines);
+  } else {
+    return (1, @unicode_lines);
+  }
+}
+
+# check if the given unicode string contain unicode whitespaces
+# other than the usual four: TAB, LF, CR and SPACE
+sub validate_utf8_whitespaces {
+  my $unicode_lines = shift;
+  use feature 'unicode_strings';
+  for (my $i = 0; $i < scalar @{$unicode_lines}; $i++) {
+    my $current_line = $unicode_lines->[$i];
+    # we replace TAB, LF, CR, and SPACE
+    # this is to simplify the test
+    $current_line =~ s/[\x{0009}\x{000a}\x{000d}\x{0020}]/./g;
+    if ($current_line =~/\s/) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+# checks if the text in the file (supplied as the argument) is utf-8 compatible
+# if yes, checks if it contains only allowed whitespaces. If no, then does not
+# do anything. The function seeks to the original position in the file after
+# reading the text.
+sub check_allowed_whitespace {
+  my $file = shift;
+  my $pos = tell($file);
+  (my $is_utf, my @lines) = get_utf8_or_bytestream($file);
+  seek($file, $pos, SEEK_SET);
+  if ($is_utf) {
+    my $has_invalid_whitespaces = validate_utf8_whitespaces(\@lines);
+    print "--> text seems to be UTF-8 or ASCII, checking whitespaces\n";
+    if ($has_invalid_whitespaces) {
+      print "--> ERROR: the text containes disallowed UTF-8 whitespace character(s)\n";
+      return 0;
+    } else {
+      print "--> text contains only allowed whitespaces\n";
+    }
+  } else {
+    print "--> text doesn't seem to be UTF-8 or ASCII, won't check whitespaces\n";
+  }
+  return 1;
+}
 
 $skip_det_check = 0;
 $skip_disambig_check = 0;
@@ -44,6 +127,7 @@ if (!open(P, "<$lang/phones.txt")) {
 }
 $idx = 1;
 %psymtab = ();
+check_allowed_whitespace(\*P) or exit 1;
 while (<P>) {
   chomp;
   my @col = split(" ", $_);
@@ -77,6 +161,7 @@ if (!open(W, "<$lang/words.txt")) {
 }
 $idx = 1;
 %wsymtab = ();
+check_allowed_whitespace(\*W) or exit 1;
 while (<W>) {
   chomp;
   my @col = split(" ", $_);
@@ -124,6 +209,7 @@ sub check_txt_int_csl {
   }
 
   $idx1 = 1;
+  check_allowed_whitespace(\*TXT) or $exit = 1;
   while (<TXT>) {
     chomp;
     my @col = split(" ", $_);
@@ -202,6 +288,7 @@ sub check_txt_int {
   }
 
   $idx1 = 1;
+  check_allowed_whitespace(\*TXT) or $exit = 1;
   while (<TXT>) {
     chomp;
     s/^(shared|not-shared) (split|not-split) //g;
diff --git a/egs/wsj/s5/utils/validate_text.pl b/egs/wsj/s5/utils/validate_text.pl
new file mode 100755 (executable)
index 0000000..9f8c8df
--- /dev/null
@@ -0,0 +1,131 @@
+#!/usr/bin/env perl
+#===============================================================================
+# Copyright 2017  (Author: Yenda Trmal <jtrmal@gmail.com>)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+# MERCHANTABLITY OR NON-INFRINGEMENT.
+# See the Apache 2 License for the specific language governing permissions and
+# limitations under the License.
+#===============================================================================
+
+# validation script for data/<dataset>/text
+# to be called (preferably) from utils/validate_data_dir.sh
+use strict;
+use warnings;
+use utf8;
+use Fcntl qw< SEEK_SET >;
+
+# this function reads the opened file (supplied as a first
+# parameter) into an array of lines. For each
+# line, it tests whether it's a valid utf-8 compatible
+# line. If all lines are valid utf-8, it returns the lines
+# decoded as utf-8, otherwise it assumes the file's encoding
+# is one of those 1-byte encodings, such as ISO-8859-x
+# or Windows CP-X.
+# Please recall we do not really care about
+# the actually encoding, we just need to
+# make sure the length of the (decoded) string
+# is correct (to make the output formatting looking right).
+sub get_utf8_or_bytestream {
+  use Encode qw(decode encode);
+  my $is_utf_compatible = 1;
+  my @unicode_lines;
+  my @raw_lines;
+  my $raw_text;
+  my $lineno = 0;
+  my $file = shift;
+
+  while (<$file>) {
+    $raw_text = $_;
+    last unless $raw_text;
+    if ($is_utf_compatible) {
+      my $decoded_text = eval { decode("UTF-8", $raw_text, Encode::FB_CROAK) } ;
+      $is_utf_compatible = $is_utf_compatible && defined($decoded_text);
+      push @unicode_lines, $decoded_text;
+    } else {
+      #print STDERR "WARNING: the line $raw_text cannot be interpreted as UTF-8: $decoded_text\n";
+      ;
+    }
+    push @raw_lines, $raw_text;
+    $lineno += 1;
+  }
+
+  if (!$is_utf_compatible) {
+    return (0, @raw_lines);
+  } else {
+    return (1, @unicode_lines);
+  }
+}
+
+# check if the given unicode string contain unicode whitespaces
+# other than the usual four: TAB, LF, CR and SPACE
+sub validate_utf8_whitespaces {
+  my $unicode_lines = shift;
+  use feature 'unicode_strings';
+  for (my $i = 0; $i < scalar @{$unicode_lines}; $i++) {
+    my $current_line = $unicode_lines->[$i];
+    # we replace TAB, LF, CR, and SPACE
+    # this is to simplify the test
+    $current_line =~ s/[\x{0009}\x{000a}\x{000d}\x{0020}]/./g;
+    if ($current_line =~/\s/) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+# checks if the text in the file (supplied as the argument) is utf-8 compatible
+# if yes, checks if it contains only allowed whitespaces. If no, then does not
+# do anything. The function seeks to the original position in the file after
+# reading the text.
+sub check_allowed_whitespace {
+  my $file = shift;
+  my $pos = tell($file);
+  (my $is_utf, my @lines) = get_utf8_or_bytestream($file);
+  seek($file, $pos, SEEK_SET);
+  if ($is_utf) {
+    my $has_invalid_whitespaces = validate_utf8_whitespaces(\@lines);
+    print "--> text seems to be UTF-8 or ASCII, checking whitespaces\n";
+    if ($has_invalid_whitespaces) {
+      print "--> ERROR: the text containes disallowed UTF-8 whitespace character(s)\n";
+      return 0;
+    } else {
+      print "--> text contains only allowed whitespaces\n";
+    }
+  } else {
+    print "--> text doesn't seem to be UTF-8 or ASCII, won't check whitespaces\n";
+  }
+  return 1;
+}
+if(@ARGV != 1) {
+  die "Usage: validate_text.pl <text-file>\n" .
+      "e.g.: validate_text.pl data/train/text\n";
+}
+
+my $text = shift @ARGV;
+
+# Checking optional_silence.txt -------------------------------
+print "Checking $text ...\n";
+if(-z "$text") {
+  print "--> ERROR: $text is empty or not exists\n";
+  exit 1;
+}
+
+if(!open(FILE, "<$text")) {
+  print "--> ERROR: fail to open $text\n";
+  exit 1;
+}
+
+print "--> reading $text\n";
+check_allowed_whitespace(\*FILE) or exit 1;
+close(FILE);
+
+