0

0

二维数组字符串边界检查与安全放置策略

霞舞

霞舞

发布时间:2025-10-31 18:41:00

|

913人浏览过

|

来源于php中文网

原创

二维数组字符串边界检查与安全放置策略

本文旨在探讨在java中向二维字符数组(如用于实现单词搜索板)添加字符串时,如何有效进行边界检查,以避免索引越界错误和字符截断。我们将分析常见的错误模式,并提供一个健壮的解决方案,包括预先检查单词是否能完整放置的逻辑,以及优化字符逐个放置的实现,确保数据操作的安全性与准确性。

1. 二维数组中字符串放置的挑战

在开发涉及二维字符数组(例如,一个简单的单词搜索游戏板)的应用时,一个常见需求是将一个字符串(单词)放置到数组的特定位置。然而,如果未进行充分的边界检查,很容易导致以下问题:

  • ArrayIndexOutOfBoundsException:当尝试访问超出数组索引范围的位置时抛出。
  • 字符串截断:单词的一部分被成功放置,但超出数组边界的部分被无声地丢弃,导致数据不完整。

原始代码示例中,尝试在 WordSearch 类中通过 addWord 方法向 char board[][] 添加单词时,就遇到了上述问题。其核心问题在于边界检查逻辑不完善以及循环内部索引更新的副作用。

public class WordSearch {

    private static int rows = 5;
    private static int columns = 10;
    char board[][] = new char [rows][columns];

    public WordSearch(){
        for(int row=0; row<rows; row++){
            for(int col=0; col<columns; col++){
                board[row][col] = '*'; // 初始化为 '*'
            }
        }
    }

    public void addWord(String word, int position, int x , int y) {
        // position 0: 水平, 1: 垂直
        switch(position){
            case 0: // 水平放置
                for(int i=0; i<word.length(); i++){
                    // 错误:检查条件 'y + 1' 可能导致当前字符已越界但仍在尝试写入
                    // 并且 y++ 在赋值后执行,影响下一次循环的判断
                    if(y + 1 >= board[x].length){ 
                        continue; // 继续下一字符,但当前字符已丢失
                    } else if(board[x][y] == '*'){ // 这里的 if/else 结构是冗余的
                        board[x][y++] = word.charAt(i);
                    } else {
                        board[x][y++] = word.charAt(i);
                    }
                }
                break;
            case 1: // 垂直放置
                for(int i=0; i<word.length(); i++){
                    // 错误:类似水平放置的问题
                    if(x + 1 >= board[y].length){ // 注意这里使用了 board[y].length,应该是 board.length
                        continue;
                    } else if(board[x][y] == '*'){
                        board[x++][y] = word.charAt(i);
                    } else {
                        board[x++][y] = word.charAt(i);
                    }
                }
                break;
            default:
                System.out.println("Give 0 to add word horizontally, or 1 vertically");
        }
    }
}

上述代码存在几个关键问题:

  1. 不正确的边界检查条件:if(y + 1 >= board[x].length) 应该改为 if(y >= board[x].length)。y + 1 是检查下一个位置,而我们首先需要确保当前 y 值是合法的。
  2. y++ (或 x++) 的副作用:在 board[x][y++] = word.charAt(i); 这样的语句中,y 会在赋值操作完成后立即递增。这意味着在循环的下一次迭代中,if 条件会使用已经递增的 y 值进行判断,这可能导致判断逻辑混乱。
  3. 缺乏整体性检查:当前代码是逐个字符地检查是否能放置,而不是在放置前整体判断整个单词是否能完整放入。这可能导致部分单词被放置,而部分被截断。
  4. 垂直放置的维度错误:if(x + 1 >= board[y].length) 中的 board[y].length 是错误的,对于二维数组,行数应是 board.length,列数应是 board[0].length。垂直放置时,应该检查 x 是否越界,即 x >= board.length。

2. 改进的边界检查与单词放置策略

为了解决上述问题,我们应采取两步策略:

  1. 预先检查:在尝试放置任何字符之前,先判断整个单词是否能从指定起始位置完整地放置到数组中。
  2. 精确放置:如果预检查通过,则逐字符地将单词放置到数组中,确保索引的正确更新。

2.1 预检查单词是否可放置 (canPlaceWord 方法)

引入一个辅助方法 canPlaceWord,用于在实际修改数组前,判断一个单词是否能在指定方向和起始坐标下完全容纳。

PixVerse
PixVerse

PixVerse是一款强大的AI视频生成工具,可以轻松地将多种输入转化为令人惊叹的视频。

下载
public boolean canPlaceWord(String word, int position, int startX, int startY) {
    if (word == null || word.isEmpty()) {
        return true; // 空单词总是可以放置的,或者根据业务需求返回 false
    }

    // 检查起始坐标是否越界
    if (startX < 0 || startX >= rows || startY < 0 || startY >= columns) {
        return false;
    }

    int wordLength = word.length();

    if (position == 0) { // 水平放置
        // 检查单词的结束位置是否在数组边界内
        if (startY + wordLength > columns) {
            return false;
        }
        // 可选:检查路径上是否有其他非'*'字符,如果要求不覆盖
        for (int i = 0; i < wordLength; i++) {
            if (board[startX][startY + i] != '*') {
                // 如果需要覆盖现有字符,则移除此检查
                // 如果不允许覆盖,则返回 false
                // return false; 
            }
        }
    } else if (position == 1) { // 垂直放置
        // 检查单词的结束位置是否在数组边界内
        if (startX + wordLength > rows) {
            return false;
        }
        // 可选:检查路径上是否有其他非'*'字符
        for (int i = 0; i < wordLength; i++) {
            if (board[startX + i][startY] != '*') {
                // return false;
            }
        }
    } else {
        return false; // 无效的放置方向
    }
    return true;
}

2.2 优化 addWord 方法

在 addWord 方法中调用 canPlaceWord 进行预检查,如果通过,则执行精确的字符放置。

public class WordSearch {

    private static int rows = 5;
    private static int columns = 10;
    char board[][] = new char [rows][columns];

    public WordSearch(){
        for(int row=0; row<rows; row++){
            for(int col=0; col<columns; col++){
                board[row][col] = '*';
            }
        }
    }

    // 辅助方法:打印当前板子状态
    public void printBoard() {
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < columns; c++) {
                System.out.print(board[r][c] + " ");
            }
            System.out.println();
        }
        System.out.println("--------------------");
    }

    /**
     * 检查单词是否可以在指定位置和方向上完整放置。
     * @param word 待放置的单词
     * @param position 放置方向 (0: 水平, 1: 垂直)
     * @param startX 起始行索引
     * @param startY 起始列索引
     * @return 如果可以放置则返回 true,否则返回 false
     */
    public boolean canPlaceWord(String word, int position, int startX, int startY) {
        if (word == null || word.isEmpty()) {
            return true; // 空单词视为可放置,或者根据需求返回 false
        }

        // 检查起始坐标是否越界
        if (startX < 0 || startX >= rows || startY < 0 || startY >= columns) {
            return false;
        }

        int wordLength = word.length();

        if (position == 0) { // 水平放置
            // 检查单词结束位置是否超出列边界
            if (startY + wordLength > columns) {
                return false;
            }
            // (可选) 如果不允许覆盖非 '*' 字符,可以在这里添加检查
            // for (int i = 0; i < wordLength; i++) {
            //     if (board[startX][startY + i] != '*') {
            //         return false;
            //     }
            // }
        } else if (position == 1) { // 垂直放置
            // 检查单词结束位置是否超出行边界
            if (startX + wordLength > rows) {
                return false;
            }
            // (可选) 如果不允许覆盖非 '*' 字符,可以在这里添加检查
            // for (int i = 0; i < wordLength; i++) {
            //     if (board[startX + i][startY] != '*') {
            //         return false;
            //     }
            // }
        } else {
            return false; // 无效的放置方向
        }
        return true;
    }

    /**
     * 将单词添加到二维数组中。
     * @param word 待添加的单词
     * @param position 放置方向 (0: 水平, 1: 垂直)
     * @param startX 起始行索引
     * @param startY 起始列索引
     * @return 如果成功添加则返回 true,否则返回 false
     */
    public boolean addWord(String word, int position, int startX, int startY) {
        // 首先进行预检查
        if (!canPlaceWord(word, position, startX, startY)) {
            System.out.println("Error: Word '" + word + "' cannot be placed at (" + startX + "," + startY + ") with position " + position + " due to boundary or existing characters.");
            return false;
        }

        // 预检查通过,开始放置单词
        switch(position){
            case 0: // 水平放置
                for(int i = 0; i < word.length(); i++){
                    board[startX][startY + i] = word.charAt(i);
                }
                break;
            case 1: // 垂直放置
                for(int i = 0; i < word.length(); i++){
                    board[startX + i][startY] = word.charAt(i);
                }
                break;
            default:
                // canPlaceWord 已经处理了无效 position,这里理论上不会执行
                System.out.println("Invalid position. Use 0 for horizontal or 1 for vertical.");
                return false;
        }
        return true;
    }

    public static void main(String[] args) {
        WordSearch ws = new WordSearch();
        ws.printBoard();

        // 尝试放置一个能放下的单词
        ws.addWord("schedule", 0, 2, 0); // 从 (2,0) 水平放置 "schedule"
        ws.printBoard();

        // 尝试放置一个部分越界的单词 (水平)
        ws.addWord("ridiculous", 0, 3, 5); // 从 (3,5) 水平放置 "ridiculous" (长度10,列宽10,5+10=15 > 10)
        ws.printBoard(); // 应该显示错误信息,板子不变

        // 尝试放置一个完全越界的单词 (垂直)
        ws.addWord("longword", 1, 3, 2); // 从 (3,2) 垂直放置 "longword" (长度8,行高5,3+8=11 > 5)
        ws.printBoard(); // 应该显示错误信息,板子不变

        // 尝试放置一个能放下的单词 (垂直)
        ws.addWord("relax", 1, 0, 5); // 从 (0,5) 垂直放置 "relax"
        ws.printBoard();

        // 再次尝试放置一个能放下的单词 (水平)
        ws.addWord("test", 0, 4, 6); // 从 (4,6) 水平放置 "test" (长度4,列宽10,6+4=10 <= 10)
        ws.printBoard();
    }
}

在上述优化后的代码中:

  • addWord 方法现在首先调用 canPlaceWord 来判断整个单词是否可以放置。
  • 如果 canPlaceWord 返回 false,则 addWord 会打印错误信息并返回 false,表示放置失败。
  • 如果 canPlaceWord 返回 true,则 addWord 确保单词的每个字符都安全地放置到数组中,通过 startY + i 或 startX + i 来正确计算每个字符的位置,而不再使用 y++ 或 x++ 这种可能导致混淆的后增量操作。

3. 注意事项与最佳实践

  1. 分离职责:将“检查是否可放置”的逻辑封装在 canPlaceWord 方法中,与“实际放置”的逻辑 addWord 分离,使代码更清晰、更易于维护和测试。
  2. 明确返回值:addWord 方法现在返回一个布尔值,指示操作是否成功。这使得调用者可以根据返回值进行后续处理,例如重试、提示用户等。
  3. 处理空字符串:canPlaceWord 方法中对空字符串的处理应根据具体业务需求决定。当前代码将其视为可放置,但也可以选择返回 false。
  4. 覆盖策略:canPlaceWord 中注释掉的部分展示了如何添加逻辑来检查目标位置是否已被其他非 * 字符占据。如果您的应用程序不允许覆盖现有字符,则应启用并完善此检查。
  5. 维度一致性:对于二维数组 char[][] board,board.length 表示行数,board[0].length (或 columns) 表示列数。在进行垂直放置时,检查行索引是否越界;水平放置时,检查列索引是否越界。
  6. 错误信息:提供清晰的错误信息对于调试和用户反馈至关重要。

4. 总结

在Java中向二维数组添加字符串时,进行严格而全面的边界检查是确保程序健壮性的关键。通过将“能否放置”的判断逻辑与“实际放置”的执行逻辑分离,并采用预先检查整个单词长度的策略,可以有效地避免 ArrayIndexOutOfBoundsException 和数据截断问题。这种结构不仅提高了代码的可靠性,也使其更易于理解和扩展,是处理类似数组操作时的推荐做法。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

761

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1570

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

651

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1228

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

1205

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

193

2025.07.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.3万人学习

Java 教程
Java 教程

共578课时 | 82.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号