{ }codelper
リストに含まれるか文字列の繰り返しP0194

チャットの禁止語を隠す

ゲームのチャットルームが、禁止語をアスタリスクで隠す。
一行目に禁止語の数 n、二行目に禁止語 n 個が空白区切りで与えられる。
三行目にチャットが一行与えられる。
チャットは英小文字の単語が空白一つずつで区切られている。
チャットの単語のうち、禁止語のリストにある単語とまるごと同じ単語は、その単語の文字数だけのアスタリスク(*)に置き換える。
禁止語がほかの単語の一部として入っているだけなら、その単語は置き換えない。
たとえば禁止語が cat でも category はそのままにする。
禁止語のリストに同じ単語が二回出てくることもある。
置き換えたチャットを、単語の間に空白を一つずつ置いて一行に出力せよ。

入力
1 ≤ n ≤ 100、チャットの単語数 1〜1,000、禁止語と単語は英小文字 1〜20 文字
出力
隠したチャットを一行
例 1 · stdin
2
cat dog
the cat sat on a category of dogs with a dog
stdout
the *** sat on a category of dogs with a ***
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

「リストにあるか」と「文字列の中にあるか」を取り違えるのがこの問題の落とし穴です。
同じ名前の操作が二つの意味を持っています。
Python の in は、リストでは等しい要素を、文字列では部分文字列を探します。
禁止語の行を split() せずに文字列のまま置くと、"at" in "cat dog" が真になります。
JS・TS の includes も、配列では等しい要素、文字列では部分文字列です。
Craykon の 含む もリストと文字列で同じ違いがあります。
Java は List.contains、C# は List.Contains(配列なら LINQ の Contains か Array.IndexOf)、C++ は std::find(v.begin(), v.end(), w) != v.end() です。
std::vector には contains がありません(C++23 からはアルゴリズム std::ranges::contains(v, w) もあります)。
C にはリスト検索がないので、ループと strcmp で自分で探します。
C で == で比べると内容ではなくアドレスを比べるので、一つも当たりません。
行全体に replace を使うと category の中の cat まで隠れるので、単語ごとに聞く必要があります。
アスタリスクを作る:Python "*" * len(w)、JS・TS・Java "*".repeat(n)、C# new string('*', n)、C++ std::string(n, '*')、Craykon "*".繰り返し(n)、C は putchar を n 回です。

Pythonmain.py · 10 行
n = int(input())banned = input().split()   # 문자열이 아니라 낱말 목록으로 둔다words = input().split()out = []for w in words:    if w in banned:        # 목록에서 통째로 같은 낱말을 찾는다        out.append("*" * len(w))    else:        out.append(w)print(" ".join(out))
JavaScriptmain.js · 6 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const banned = lines[1].trim().split(/\s+/); // 낱말 배열const words = lines[2].trim().split(/\s+/);// 배열의 includes는 같은 낱말을 찾는다(문자열의 includes는 부분 문자열을 찾는다)const out = words.map((w) => (banned.includes(w) ? "*".repeat(w.length) : w));console.log(out.join(" "));
TypeScriptmain.ts · 7 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const banned: string[] = lines[1].trim().split(/\s+/); // 낱말 배열const words: string[] = lines[2].trim().split(/\s+/);// 배열의 includes는 같은 낱말을 찾는다(문자열의 includes는 부분 문자열을 찾는다)const out: string[] = words.map((w) => (banned.includes(w) ? "*".repeat(w.length) : w));console.log(out.join(" "));
JavaMain.java · 20 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.Arrays;import java.util.List; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        in.readLine();        List<String> banned = Arrays.asList(in.readLine().trim().split(" "));        String[] words = in.readLine().trim().split(" ");        StringBuilder out = new StringBuilder();        for (int i = 0; i < words.length; i++) {            if (i > 0) out.append(' ');            // List.contains는 equals로 비교한다(==는 같은 객체인지를 본다)            out.append(banned.contains(words[i]) ? "*".repeat(words[i].length()) : words[i]);        }        System.out.println(out);    }}
C#Main.cs · 21 行
using System;using System.Collections.Generic; class Program{    static void Main()    {        Console.ReadLine();        var banned = new List<string>(Console.ReadLine().Trim().Split(' '));        string[] words = Console.ReadLine().Trim().Split(' ');        for (int i = 0; i < words.Length; i++)        {            // List.Contains는 낱말이 통째로 같은지 본다            if (banned.Contains(words[i]))            {                words[i] = new string('*', words[i].Length);            }        }        Console.WriteLine(string.Join(" ", words));    }}
C++main.cpp · 21 行
#include <algorithm>#include <iostream>#include <string>#include <vector> int main() {    int n;    std::cin >> n;    std::vector<std::string> banned(n);    for (auto& b : banned) std::cin >> b;    std::string w;    bool first = true;    while (std::cin >> w) {        if (!first) std::cout << ' ';        first = false;        // std::find로 같은 낱말을 찾는다(vector에는 contains 멤버가 없다)        bool hit = std::find(banned.begin(), banned.end(), w) != banned.end();        std::cout << (hit ? std::string(w.size(), '*') : w);    }    std::cout << '\n';}
Cmain.c · 31 行
#include <stdio.h>#include <string.h> static char banned[100][21];static int n; /* 목록에 같은 낱말이 있나: 내용 비교는 strcmp(==는 주소를 비교한다) */int contains(const char *w) {    for (int i = 0; i < n; i++) {        if (strcmp(banned[i], w) == 0) return 1;    }    return 0;} int main(void) {    char w[21];    scanf("%d", &n);    for (int i = 0; i < n; i++) scanf("%20s", banned[i]);    int first = 1;    while (scanf("%20s", w) == 1) {        if (!first) putchar(' ');        first = 0;        if (contains(w)) {            for (size_t k = 0; k < strlen(w); k++) putchar('*');        } else {            fputs(w, stdout);        }    }    putchar('\n');    return 0;}
Craykonmain.cray · 17 行
n = コンソール.行読み().数に();banned = コンソール.行読み().空白除去().分ける(); // 낱말 목록words = コンソール.行読み().空白除去().分ける();out = [];それぞれ (w の中 words){    // 목록의 있나는 같은 낱말을 찾는다(문자열의 있나는 부분 문자열을 찾는다)    もし (banned.含む(w))    {        out.追加("*".繰り返し(w.長さ));    }    でなければ    {        out.追加(w);    }}コンソール.書く(out.つなぐ(" "));