Ruby: J'ai essayé de savoir où Nokogiri va voir l'encodage lui-même

introduction

Dans un article ici, Nokogiri conclut que lorsque la spécification d'encodage est «nil», il va voir le jeu de caractères du méta élément du html original. J'ai fait. Cette fois, j'ai suivi la documentation officielle pour voir si les conclusions se sont réellement réalisées.

Suivez la documentation officielle

Document officiel de Nokogiri Cette fois, je suivrai ce document officiel. Bien sûr, c'est l'anglais. J'évite généralement les documents officiels en anglais, mais je décide d'aller les voir. Même si vous ne pouvez pas lire l'anglais, vous pouvez lire le code. Peut-être.

Classe Nokogiri :: HTML :: Document

Normalement, lors de l'analyse en utilisant Nokogiri, il est écrit comme Nokogiri :: HTML.parse (html), mais officiellement il semble être la classe Nokogiri :: HTML :: Document. Ouvrez le champ Classe de document, recherchez la méthode .parse et essayez d'afficher la source avec" afficher la source ".

Source ci-dessous

lib/nokogiri/html/document.rb


def parse string_or_io, url = nil, encoding = nil, options = XML::ParseOptions::DEFAULT_HTML

  options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
  # Give the options to the user
  yield options if block_given?

  if string_or_io.respond_to?(:encoding)
    unless string_or_io.encoding.name == "ASCII-8BIT"
      encoding ||= string_or_io.encoding.name
    end
  end

  if string_or_io.respond_to?(:read)
    url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
    unless encoding
      # Libxml2's parser has poor support for encoding
      # detection.  First, it does not recognize the HTML5
      # style meta charset declaration.  Secondly, even if it
      # successfully detects an encoding hint, it does not
      # re-decode or re-parse the preceding part which may be
      # garbled.
      #
      # EncodingReader aims to perform advanced encoding
      # detection beyond what Libxml2 does, and to emulate
      # rewinding of a stream and make Libxml2 redo parsing
      # from the start when an encoding hint is found.
      string_or_io = EncodingReader.new(string_or_io)
      begin
        return read_io(string_or_io, url, encoding, options.to_i)
      rescue EncodingFound => e
        encoding = e.found_encoding
      end
    end
    return read_io(string_or_io, url, encoding, options.to_i)
  end

  # read_memory pukes on empty docs
  if string_or_io.nil? or string_or_io.empty?
    return encoding ? new.tap { |i| i.encoding = encoding } : new
  end

  encoding ||= EncodingReader.detect_encoding(string_or_io)

  read_memory(string_or_io, url, encoding, options.to_i)
end

Faisons attention ici en premier

lib/nokogiri/html/document.rb


  if string_or_io.respond_to?(:encoding)
    unless string_or_io.encoding.name == "ASCII-8BIT"
      encoding ||= string_or_io.encoding.name
    end
  end

string_or_io est une variable que vous spécifiez généralement html. En interprétant, si string_or_io a une méthode ʻencoding, son nom de codage n'est pas ʻASCII-8BIT, et l'argument ʻencoding n'est pas défini, alors ʻencoding est string_or_io. Cela semble être le nom du codage.

Je vois! Donc, si vous n'ouvrez pas html en mode binaire, cela dépend de la façon dont vous ouvrez html (encodage), donc des caractères déformés peuvent se produire après l'analyse!

Alors, que se passe-t-il lorsque vous ouvrez le fichier en mode binaire et que l'argument ʻencoding est nil`? Maintenant, concentrons-nous sur ici.

lib/nokogiri/html/document.rb


encoding ||= EncodingReader.detect_encoding(string_or_io)

Si l'argument ʻencoding n'est pas défini, vous pouvez utiliser la méthode ʻEncodingReader.detect_encoding. Allez doucement à la méthode ʻEncodingReader.detect_encoding` du document.

Affichez la source comme avant. Source ci-dessous

lib/nokogiri/html/document.rb


def self.detect_encoding(chunk)
  if Nokogiri.jruby? && EncodingReader.is_jruby_without_fix?
    return EncodingReader.detect_encoding_for_jruby_without_fix(chunk)
  end
  m = chunk.match(/\A(<\?xml[ \t\r\n]+[^>]*>)/) and
    return Nokogiri.XML(m[1]).encoding

  if Nokogiri.jruby?
    m = chunk.match(/(<meta\s)(.*)(charset\s*=\s*([\w-]+))(.*)/i) and
      return m[4]
    catch(:encoding_found) {
      Nokogiri::HTML::SAX::Parser.new(JumpSAXHandler.new(:encoding_found)).parse(chunk)
      nil
    }
  else
    handler = SAXHandler.new
    parser = Nokogiri::HTML::SAX::PushParser.new(handler)
    parser << chunk rescue Nokogiri::SyntaxError
    handler.encoding
  end
end

L'argument de méthode chunk contiendra string_or_io cette fois, c'est-à-dire ce que vous utilisez normalement comme HTML.

Il existe de nombreuses méthodes inconnues, donc je ne peux pas obtenir la signification exacte, mais y a-t-il une description qui fait référence au jeu de caractères de meta dans le second bloc if? ?? ?? Il semble que la valeur soit retournée par retour, et cette partie semble très suspecte.

à la fin

Je n'ai pas encore trouvé les détails de la source, mais j'ai l'impression de me rapprocher de la réponse que je recherche. Si je connais les détails de la source, je vais la résumer dans un autre article.

Recommended Posts

Ruby: J'ai essayé de savoir où Nokogiri va voir l'encodage lui-même
J'ai essayé de découvrir ce qui avait changé dans Java 9
J'ai brièvement résumé la grammaire de base de Ruby
J'ai essayé d'expliquer la méthode
J'ai essayé de résoudre le problème de la "sélection multi-étapes" avec Ruby
[Metal] J'ai essayé de comprendre le flux jusqu'au rendu avec Metal
[Rubiy] J'ai essayé de résumer le traitement de la boucle ce soir [fois, pause ...]
J'ai essayé de résumer les méthodes utilisées
J'ai essayé d'implémenter le modèle Iterator
J'ai essayé de résoudre le problème de la séquence Tribonacci en Ruby, avec récurrence.
J'ai essayé de résumer l'API Stream
Où puis-je trouver des informations sur les versions de Java après février 2019? À propos du problème
J'ai essayé d'utiliser pleinement le cœur du processeur avec Ruby
[Ruby] J'ai essayé de résumer les méthodes fréquentes dans paiza
J'ai essayé de comprendre la relation entre des classes telles que java.io.InputStream
[Ruby] J'ai essayé de résumer les méthodes fréquentes avec paiza ②
J'ai essayé de résoudre le problème de la séquence Tribonacci en Ruby (temps limite 10 minutes)
Comment trouver la cause de l'erreur Ruby
[Rails] J'ai essayé de faire passer la version de Rails de 5.0 à 5.2
J'ai essayé d'organiser la session en Rails
[Notions de base sur Ruby] J'ai essayé d'apprendre des modules (Chapitre 1)
J'ai essayé de configurer tomcat pour exécuter le servlet.
Je veux obtenir la valeur en Ruby
05. J'ai essayé de supprimer la source de Spring Boot
J'ai essayé de réduire la capacité de Spring Boot
J'ai essayé d'implémenter la méthode de division mutuelle d'Eugrid en Java
Je veux savoir quelle version de java le fichier jar que j'ai est disponible
J'ai dû déterminer où se trouvait le dossier des plugins eclipse sur mon Mac. (Note)
J'ai essayé de résoudre le problème de la machine à karaoké Ruby (il y a un exemple de réponse)
J'ai essayé de résoudre le problème de la boisson bonus Ruby (il y a un exemple de réponse)
[SwiftUI] J'ai essayé de découvrir comment cela change pour chaque emplacement spécifié de l'arrière-plan
Je veux savoir si la chaîne de caractères spécifiée est prise en charge par le code de caractère cible
Je ne trouve pas l'image du docker après la mise à jour vers Docker Desktop 2.4.0.0
J'ai essayé d'implémenter la fonction similaire par communication asynchrone
J'ai essayé d'augmenter la vitesse de traitement avec l'ingénierie spirituelle
[JDBC] J'ai essayé d'accéder à la base de données SQLite3 depuis Java.
J'ai essayé de résumer les bases de kotlin et java
(´-`) .. oO (Je veux trouver facilement la sortie standard" Hello ".
J'ai essayé de construire l'environnement petit à petit en utilisant docker
J'ai essayé de créer un environnement de WSL2 + Docker + VSCode
J'ai essayé de valider pour unifier comment écrire des balises de hachage
[Ruby] Je souhaite inverser l'ordre de la table de hachage
J'ai essayé de résoudre le problème de création de carte de bingo Ruby (il y a un exemple de réponse)