From 2ed41acb2edf60b90e656e6aa0c22cc361ad5df0 Mon Sep 17 00:00:00 2001 From: Takuya Date: Sat, 20 Jan 2024 04:06:34 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 + jest.config.ts | 3 +- {test => src/helper/test}/helper.test.ts | 6 +- src/index.ts | 115 +----------------- src/lib/create_html_for_columns.ts | 10 ++ src/lib/format_and_split_text_Into_columns.ts | 48 ++++++++ src/lib/original_input_handler.ts | 47 +++++++ src/lib/split_into_columns.ts | 37 ++++++ src/lib/test/create_html_for_columns.test.ts | 52 ++++++++ ...format_and_split_text_Into_columns.test.ts | 85 +++++++++++++ src/lib/test/split_into_columns.test.ts | 27 ++++ 11 files changed, 315 insertions(+), 118 deletions(-) create mode 100644 .vscode/settings.json rename {test => src/helper/test}/helper.test.ts (98%) create mode 100644 src/lib/create_html_for_columns.ts create mode 100644 src/lib/format_and_split_text_Into_columns.ts create mode 100644 src/lib/original_input_handler.ts create mode 100644 src/lib/split_into_columns.ts create mode 100644 src/lib/test/create_html_for_columns.test.ts create mode 100644 src/lib/test/format_and_split_text_Into_columns.test.ts create mode 100644 src/lib/test/split_into_columns.test.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ebfde9a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true, +} \ No newline at end of file diff --git a/jest.config.ts b/jest.config.ts index 1913203..794f4a7 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -193,7 +193,8 @@ module.exports = { // watchman: true, roots: [ - "/test" + "/src/lib/test", + "/src/helper/test" ], transform: { diff --git a/test/helper.test.ts b/src/helper/test/helper.test.ts similarity index 98% rename from test/helper.test.ts rename to src/helper/test/helper.test.ts index 21a38f9..77773f6 100644 --- a/test/helper.test.ts +++ b/src/helper/test/helper.test.ts @@ -1,5 +1,5 @@ -import { Helper } from "../src/helper/helper" -import { Type } from "../src/type/type" +import { Helper } from "../helper" +import { Type } from "../../type/type" describe("Helper.delete_last_period()", () => { test("テストが正常に動作している", () => { @@ -113,4 +113,4 @@ describe("Helper.delete_last_empty_string()", () => { expect(result).toStrictEqual(correct) }) } -) \ No newline at end of file +) diff --git a/src/index.ts b/src/index.ts index 3acd2d4..0311ad2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,116 +1,3 @@ -class OriginalInputHandler { - private charLimit = 4500; - - constructor() { - this.initializeEventListeners(); - } - - private initializeEventListeners() { - window.onload = () => { - const originalElement = document.getElementById("original"); - const charLimitElement = document.getElementById("char_limit"); - - originalElement?.addEventListener("input", this.handleInput); - charLimitElement?.addEventListener("change", this.handleInput); - }; - } - - private handleInput = (): void => { - const originalElement = document.getElementById("original") as HTMLInputElement | null; - const charLimitElement = document.getElementById("char_limit") as HTMLInputElement | null; - - if (!originalElement || !charLimitElement) return; - - this.charLimit = Math.max(Number(charLimitElement.value), 1000); - charLimitElement.value = this.charLimit.toString(); - - const source = originalElement.value; - if (!source) return; - - const convertedText = this.processText(source); - this.displayConvertedText(convertedText); - } - - private processText(text: string): string { - const replacements: [RegExp, string | ((substring: string) => string)][] = [ - [/-\n/g, ""], // Removes hyphen followed by a newline - [/\n/g, " "], // Replaces newlines with spaces - [/- /g, ""], // Removes hyphens followed by a space - [/Fig\. /g, "Fig."], // Formats abbreviation for "Figure" - [/Figs\. /g, "Figs."], // Formats abbreviation for "Figures" - [/No\. /g, "No."], // Formats abbreviation for "Number" - [/Prof\. /g, "Prof."], // Formats abbreviation for "Professor" - [/Eq\. /g, "Eq."], // Formats abbreviation for "Equation" - [/et al\. /g, "et al."], // Formats "et al." - [/Dr\. /g, "Dr."], // Formats abbreviation for "Doctor" - [/e\.g\. /g, "e.g."], // Formats "e.g." - [/i\.e\. /g, "i.e."], // Formats "i.e." - [/Sec\. /g, "Sec."], // Formats abbreviation for "Section" - [/Sect\. /g, "Sect."], // Formats abbreviation for "Section" - [/2\.4 GHz/g, "2.4GHz"], // Formats specific frequency value - [/[IVXLCDM]+\.\s/g, match => match.trim() + ". "], // Formats Roman numerals followed by a period - [/\.\d+(?= [A-Z])/g, match => "[" + match + "]. "], // Formats decimal numbers followed by an uppercase letter - [/\.\d+,\d+(?= [A-Z])/g, match => "[" + match + "]. "], // Formats numbers with commas - [/\.\d+–\d+(?= [A-Z])/g, match => "[" + match + "]. "] // Formats number ranges - - ]; - - let processedText = text; - replacements.forEach(([regex, replacement]) => { - if (typeof replacement === "function") { - processedText = processedText.replace(regex, replacement); - } else { - processedText = processedText.replace(regex, replacement); - } - }); - - const sentences = processedText.split(". ").map(str => `${str}.\n`); - const formattedText = this.splitIntoColumns(sentences); - - return this.createHtmlForColumns(formattedText); - } - - - private splitIntoColumns(sentences: string[]): string[][] { - let charCount = 0; - let results: string[][] = []; - let currentColumn: string[] = []; - - sentences.forEach(sentence => { - if (charCount + sentence.length > this.charLimit) { - results.push(currentColumn); - currentColumn = []; - charCount = 0; - } - - currentColumn.push(sentence); - charCount += sentence.length; - }); - - if (currentColumn.length > 0) { - results.push(currentColumn); - } - - return results; - } - - private createHtmlForColumns(columns: string[][]): string { - return columns.map((column, index) => - `
  • - - -
  • ` - ).join(""); - } - - private displayConvertedText(html: string): void { - const convertedElement = document.getElementById("converted"); - if (!convertedElement) return; - - convertedElement.innerHTML = html; - } -} +import { OriginalInputHandler } from "./lib/original_input_handler" new OriginalInputHandler(); diff --git a/src/lib/create_html_for_columns.ts b/src/lib/create_html_for_columns.ts new file mode 100644 index 0000000..a560b77 --- /dev/null +++ b/src/lib/create_html_for_columns.ts @@ -0,0 +1,10 @@ +export function createHtmlForColumns(columns: string[][]): string { + return columns.map((column, index) => + `
  • + + +
  • ` + ).join(""); +} diff --git a/src/lib/format_and_split_text_Into_columns.ts b/src/lib/format_and_split_text_Into_columns.ts new file mode 100644 index 0000000..980975f --- /dev/null +++ b/src/lib/format_and_split_text_Into_columns.ts @@ -0,0 +1,48 @@ +import {splitIntoColumns} from './split_into_columns' + +export function formatAndSplitTextIntoColumns( + text: string, + charLimit: number, +): string[][] { + const replacements: [RegExp, string | ((substring: string) => string)][] = [ + [/-\n/g, ''], // Ensure hyphen followed by newline is completely removed + [/\n/g, " "], // Replaces newlines with spaces + [/- /g, ""], // Removes hyphens followed by a space + [/Fig\. /g, "Fig."], // Formats abbreviation for "Figure" + [/Figs\. /g, "Figs."], // Formats abbreviation for "Figures" + [/No\. /g, "No."], // Formats abbreviation for "Number" + [/Prof\. /g, "Prof."], // Formats abbreviation for "Professor" + [/Eq\. /g, "Eq."], // Formats abbreviation for "Equation" + [/et al\. /g, "et al."], // Formats "et al." + [/Dr\. /g, "Dr."], // Formats abbreviation for "Doctor" + [/e\.g\. /g, "e.g."], // Formats "e.g." + [/i\.e\. /g, "i.e."], // Formats "i.e." + [/Sec\. /g, "Sec."], // Formats abbreviation for "Section" + [/Sect\. /g, "Sect."], // Formats abbreviation for "Section" + [/2\.4 GHz/g, "2.4GHz"], // Formats specific frequency value + [/I\. /g, "I."], + [/II\. /g, "II."], + [/III\. /g, "III."], + [/IV\. /g, "IV."], + [/V\. /g, "V."], + [/VI\. /g, "VI."], + [/VII\. /g, "VII."], + [/VIII\. /g, "VIII."], + [/IX\. /g, "IX."], + [/X\. /g, "X."], + [/\.\d+,\d+(?= [A-Z])/g, match => "[" + match + "]. "], // Formats numbers with commas + [/\.\d+-\d+(?= [A-Z])/g, match => "[" + match + "]. "], // Formats number ranges + ]; + + // Process replacements + let processedText = text; + replacements.forEach(([regex, replacement]) => { + processedText = processedText.replace(regex, (match) => typeof replacement === "function" ? replacement(match) : replacement); + }); + + // Split the processed text into sentences + const sentences = processedText.split(/(?<=\.)\s/); + + // Use the splitIntoColumns function to split the sentences into columns + return splitIntoColumns(sentences, charLimit); +} diff --git a/src/lib/original_input_handler.ts b/src/lib/original_input_handler.ts new file mode 100644 index 0000000..a321959 --- /dev/null +++ b/src/lib/original_input_handler.ts @@ -0,0 +1,47 @@ +import {formatAndSplitTextIntoColumns} from './format_and_split_text_Into_columns' +import {createHtmlForColumns} from './create_html_for_columns' + +export class OriginalInputHandler { + private charLimit = 4500; + + constructor() { + this.initializeEventListeners(); + } + + private initializeEventListeners() { + window.onload = () => { + const originalElement = document.getElementById("original"); + const charLimitElement = document.getElementById("char_limit"); + + originalElement?.addEventListener("input", this.handleInput); + charLimitElement?.addEventListener("change", this.handleInput); + }; + } + + private handleInput = (): void => { + const originalElement = document.getElementById("original") as HTMLInputElement | null; + const charLimitElement = document.getElementById("char_limit") as HTMLInputElement | null; + + if (!originalElement || !charLimitElement) return; + + this.charLimit = Math.max(Number(charLimitElement.value), 1000); + charLimitElement.value = this.charLimit.toString(); + + const source = originalElement.value; + if (!source) return; + + const convertedText = formatAndSplitTextIntoColumns( + source, + this.charLimit, + ); + const html = createHtmlForColumns(convertedText) + this.displayConvertedText(html); + } + + private displayConvertedText(html: string): void { + const convertedElement = document.getElementById("converted"); + if (!convertedElement) return; + + convertedElement.innerHTML = html; + } +} diff --git a/src/lib/split_into_columns.ts b/src/lib/split_into_columns.ts new file mode 100644 index 0000000..bfced1b --- /dev/null +++ b/src/lib/split_into_columns.ts @@ -0,0 +1,37 @@ +export function splitIntoColumns( + sentences: string[], + charLimit: number, +): string[][] { + let charCount = 0; + let results: string[][] = []; + let currentColumn: string[] = []; + + sentences.forEach(sentence => { + // Check if adding this sentence exceeds charLimit or if the sentence itself exceeds charLimit + if (charCount + sentence.length > charLimit || sentence.length > charLimit) { + // Push currentColumn to results if it's not empty + if (currentColumn.length > 0) { + results.push(currentColumn); + currentColumn = []; + } + + // If the sentence itself exceeds charLimit, it should be in its own column + if (sentence.length > charLimit) { + results.push([sentence]); + // Reset charCount as the long sentence is placed in its own column + charCount = 0; + return; // Continue to next sentence + } + } + + currentColumn.push(sentence); + charCount += sentence.length; + }); + + // Push the last column if not empty + if (currentColumn.length > 0) { + results.push(currentColumn); + } + + return results; +} diff --git a/src/lib/test/create_html_for_columns.test.ts b/src/lib/test/create_html_for_columns.test.ts new file mode 100644 index 0000000..aefd035 --- /dev/null +++ b/src/lib/test/create_html_for_columns.test.ts @@ -0,0 +1,52 @@ +import { createHtmlForColumns } from '../create_html_for_columns' + +describe('createHtmlForColumns', () => { + test('should return an empty string for an empty array', () => { + const result = createHtmlForColumns([]); + expect(result).toBe(''); + }); + + test('should handle a single-element array', () => { + const columns = [['Hello']]; + const expected = + `
  • + + +
  • `; + const result = createHtmlForColumns(columns); + expect(result).toBe(expected); + }); + + test('should handle a single-element array', () => { + const columns = [['Hello.', 'Hello']]; + const expected = + `
  • + + +
  • `; + const result = createHtmlForColumns(columns); + expect(result).toBe(expected); + }); + + test('should handle multiple elements in array', () => { + const columns = [['Hello'], ['World']]; + const expected = + `
  • + + +
  • + + +
  • `; + const result = createHtmlForColumns(columns); + expect(result).toBe(expected); + }); +}); diff --git a/src/lib/test/format_and_split_text_Into_columns.test.ts b/src/lib/test/format_and_split_text_Into_columns.test.ts new file mode 100644 index 0000000..4e96d6b --- /dev/null +++ b/src/lib/test/format_and_split_text_Into_columns.test.ts @@ -0,0 +1,85 @@ +import { formatAndSplitTextIntoColumns } from "../format_and_split_text_Into_columns" + + +describe('formatAndSplitTextIntoColumns', () => { + // Test Text Processing + it('should apply all text processing rules correctly', () => { + const testString = "This is a test-\nstring with various rules like Fig. 1, 2.4 GHz, and e.g. example."; + const expectedResult = "This is a teststring with various rules like Fig.1, 2.4GHz, and e.g.example."; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain(expectedResult); + }); + + // Test Edge Cases + it('should handle empty strings', () => { + const result = formatAndSplitTextIntoColumns('', 100); + expect(result).toEqual([['']]); + }); + + // Test Overall Functionality + it('should process and split text correctly', () => { + const testString = "This is a test-\nstring with various rules like Fig. 1, 2.4 GHz. This part will be in a separate column."; + const charLimit = 10; + const expectedResult = [ + ['This is a teststring with various rules like Fig.1, 2.4GHz.'], + ['This part will be in a separate column.'] + ]; + const result = formatAndSplitTextIntoColumns(testString, charLimit); + expect(result).toEqual(expectedResult); + }); + + // Test for hyphen followed by newline + it('should remove hyphen followed by newline', () => { + const testString = "Test-\nString"; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain('TestString'); + }); + + // Test for newlines replaced with spaces + it('should replace newlines with spaces', () => { + const testString = "Test\nString"; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain('Test String'); + }); + + // Test for hyphens followed by a space + it('should remove hyphens followed by a space', () => { + const testString = "Test- String"; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain('TestString'); + }); + + // ... (Additional tests for each replacement rule) ... + + // Test for specific frequency value + it('should format specific frequency value', () => { + const testString = "Frequency is 2.4 GHz"; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain('2.4GHz'); + }); + + // Test for formatting numbers with commas + it('should format numbers with commas', () => { + const testString = "Figure 3.1,234 shows"; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain('Figure 3.1,234 shows'); + }); + + // ... (Additional tests for each replacement rule) ... + + // Test for Roman numerals followed by a period + it('should handle Roman numerals followed by a period', () => { + const testString = "In section IV.we discuss"; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain('In section IV.we discuss'); + }); + + // Test for number ranges + it('should format number ranges', () => { + const testString = "See pages 10.23-56 for more information"; + const result = formatAndSplitTextIntoColumns(testString, 1000); + expect(result.join(' ')).toContain('See pages 10.23-56 for more information'); + }); + + // ... (Complete the tests for all the replacement rules) ... +}); \ No newline at end of file diff --git a/src/lib/test/split_into_columns.test.ts b/src/lib/test/split_into_columns.test.ts new file mode 100644 index 0000000..0766d37 --- /dev/null +++ b/src/lib/test/split_into_columns.test.ts @@ -0,0 +1,27 @@ +import {splitIntoColumns} from '../split_into_columns' + +describe('splitIntoColumns', () => { + test('should return an empty array for an empty input array', () => { + expect(splitIntoColumns([], 10)).toEqual([]); + }); + + test('should handle a single element', () => { + expect(splitIntoColumns(['Hello'], 10)).toEqual([['Hello']]); + }); + + test('should split multiple sentences into columns correctly', () => { + expect(splitIntoColumns(['Hello', 'World'], 10)).toEqual([['Hello', 'World']]); + }); + + test('should create a new column when the char limit is reached', () => { + expect(splitIntoColumns(['Hello', 'World'], 5)).toEqual([['Hello'], ['World']]); + }); + + test('should place a long sentence in a new column', () => { + expect(splitIntoColumns(['Hello', 'VeryVeryLongWord'], 10)).toEqual([['Hello'], ['VeryVeryLongWord']]); + }); + + test('should place a long sentence in a new column', () => { + expect(splitIntoColumns(['VeryVeryLongWord', 'VeryVeryLongWord'], 10)).toEqual([['VeryVeryLongWord'], ['VeryVeryLongWord']]); + }); +});