Word Counter

Share custom commands, script functions, actor implementations and other Naninovel plug-ins you've created.
Post Reply
Elringus
admin
Posts: 521
Joined: 11 May 2020 18:03

Word Counter

Post by Elringus »

While we have word count displayed when generating localization documents, we had several requests to add a counter to be used independently of the localization utility.

Counting "scenario" words (opposed to just any word, like command IDs) in source naninovel scripts is not straightforward; you may want to count only generic text lines or include @print commands or filter-out inlined commands and/or expression functions and tags embedded in the printed text, etc.

We decided that it'd be more helpful to provide a template script, which you can modify to your needs.

The script below will count words in assigned non-dynamic localizable parameters (about all the text player will see in the game) of the scripts stored at Assets/Scripts folder. Create a WordCounter.cs script at Assets/Editor project folder and copy-paste the code below. To count words, click Naninovel -> Tools -> Count Words in the Unity editor menu and find word count message logged in the console.

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Naninovel;
using UnityEditor;
using UnityEngine;

public static class WordCounter
{
    [MenuItem("Naninovel/Tools/Count Words")]
    public static void CountWords ()
    {
        var scripts = LoadScriptsAt("Assets/Scripts");
        var wordCount = scripts.Sum(CountWordsInScript);
        Debug.Log($"Word count: {wordCount}");
    }

    private static IEnumerable<Script> LoadScriptsAt (params string[] folders)
    {
        return AssetDatabase.FindAssets("t:Naninovel.Script", folders)
            .Select(AssetDatabase.GUIDToAssetPath)
            .Select(AssetDatabase.LoadAssetAtPath<Script>);
    }

    private static int CountWordsInScript (Script script)
    {
        return script.ExtractCommands().Sum(CountWordsInCommand);
    }

    private static int CountWordsInCommand (Command command)
    {
        return command.GetType().GetFields()
            .Select(field => GetLocalizableText(field, command))
            .Sum(CountWordsInText);
    }

    private static string GetLocalizableText (FieldInfo field, Command command)
    {
        if (field.FieldType != typeof(StringParameter)) return "";
        if (!field.IsDefined(typeof(Command.LocalizableParameterAttribute))) return "";
        var parameter = (StringParameter)field.GetValue(command);
        if (!Command.Assigned(parameter) || parameter.DynamicValue) return "";
        return parameter.Value;
    }

    private static int CountWordsInText (string text)
    {
        return text.Split(default(char[]), StringSplitOptions.RemoveEmptyEntries).Length;
    }
}
Colin MacLeod
Posts: 7
Joined: 17 Jul 2022 21:09

Re: Word Counter

Post by Colin MacLeod »

I couldn't get this to work. I'm not sure why. It always counted really low for me.

As an alternative, I came up with this shell script. I was using a Mac but if you install a linux layer (e.g. WSL) for windows, you should be able to use it there too. I thought it might help someone else!

You just need to change the NANI_SCRIPT_DIR var to point to location of your script files

Code: Select all

#!/bin/zsh
# Absolute path this script is in
SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )"

NANI_SCRIPT_DIR="${SCRIPT_PATH}/../Assets/_Project/NaniScripts"
COUNT_FILE="/tmp/count-words.txt"
echo > ${COUNT_FILE}
for script in "${NANI_SCRIPT_DIR}"/*.nani; do
grep -v \[@\] "${script}" | awk '!/^\s*;/' >> ${COUNT_FILE} 
done
printf "%'.f\n" `cat /tmp/count-words.txt | wc -w` 

Note it assumes any lines containing @ are command lines and ignores those (that's the grep -v), and it also ignores lines that start with a semicolon (;) as they are comments (that's the awk).

Post Reply