اسکنر جاوا — به زبان ساده

۲۷۵ بازدید
آخرین به‌روزرسانی: ۰۶ شهریور ۱۴۰۲
زمان مطالعه: ۴ دقیقه
اسکنر جاوا — به زبان ساده

در این مقاله با شیوه استفاده از کلاس اسکنر جاوا برای خواندن ورودی‌ها جهت یافتن و رد کردن الگوها با جداکننده‌های مختلف آشنا می‌شویم.

اسکن کردن یک فایل

ابتدا به بررسی شیوه خواندن یک فایل می‌پردازیم. در مثال زیر یک فایل را که شامل عبارت Hello world است در توکن‌ها می‌خوانیم:

1@Test
2public void whenReadFileWithScanner_thenCorrect() throws IOException{
3    Scanner scanner = new Scanner(new File("test.txt"));
4 
5    assertTrue(scanner.hasNext());
6    assertEquals("Hello", scanner.next());
7    assertEquals("world", scanner.next());
8 
9    scanner.close();
10}

در کد فوق به شیوه استفاده از متد ()next برای بازگشت دادن توکن String بعدی توجه کنید. ضمناً به شیوه بستن اسکنر در زمانی که کار ما با آن به پایان می‌رسد توجه کنید.

تبدیل InputStream به رشته

در این بخش شیوه تبدیل یک InputStream به یک رشته جاوا را با استفاده از یک Scanner بررسی می‌کنیم:

1@Test
2public void whenConvertInputStreamToString_thenConverted()
3  throws IOException {
4    String expectedValue = "Hello world";
5    FileInputStream inputStream 
6      = new FileInputStream("test.txt");
7     
8    Scanner scanner = new Scanner(inputStream);
9    scanner.useDelimiter("A");
10 
11    String result = scanner.next();
12    assertEquals(expectedValue, result);
13 
14    scanner.close();
15}

همانند مثال قبل در اینجا نیز از Scanner برای توکن‌دار کردن کل استریم از آغاز تا ریجکس A بعدی که با ورودی کامل انطباق می‌یابد، استفاده کرده‌ایم.

تفاوت اسکنر با BufferedReader

اکنون به بررسی تفاوت بین اسکنر با BufferedReader می‌پردازیم. به طور کلی:

  • از BufferedReader زمانی استفاده می‌کنیم که بخواهیم ورودی را درون خط‌ها قرار دهیم.
  • از اسکنر زمانی استفاده می‌کنیم که ورودی را در توکن‌ها قرار دهیم.

در مثال زیر یک فایل را با استفاده از BufferedReader در خط قرار می‌دهیم.

1@Test
2public void whenReadUsingBufferedReader_thenCorrect() 
3  throws IOException {
4    String firstLine = "Hello world";
5    String secondLine = "Hi, John";
6    BufferedReader reader 
7      = new BufferedReader(new FileReader("test.txt"));
8 
9    String result = reader.readLine();
10    assertEquals(firstLine, result);
11 
12    result = reader.readLine();
13    assertEquals(secondLine, result);
14 
15    reader.close();
16}

در مثال زیر با استفاده از Scanner همان فایل را درون توکن‌ها قرار می‌دهیم:

1@Test
2public void whenReadUsingScanner_thenCorrect() 
3  throws IOException {
4    String firstLine = "Hello world";
5    FileInputStream inputStream 
6      = new FileInputStream("test.txt");
7    Scanner scanner = new Scanner(inputStream);
8 
9    String result = scanner.nextLine();
10    assertEquals(firstLine, result);
11 
12    scanner.useDelimiter(", ");
13    assertEquals("Hi", scanner.next());
14    assertEquals("John", scanner.next());
15 
16    scanner.close();
17}

در کد فوق به شیوه استفاده از API اسکنر به نام ()nextLine برای خواندن کل خط توجه کنید.

اسکن ورودی از کنسول با اسکنر جدید System.in

در این بخش به بررسی شیوه خواندن ورودی از کنسول با استفاده از نمونه‌ای از اسکنر می‌پردازیم. به مثال زیر توجه کنید:

1@Test
2public void whenReadingInputFromConsole_thenCorrect() {
3    String input = "Hello";
4    InputStream stdin = System.in;
5    System.setIn(new ByteArrayInputStream(input.getBytes()));
6 
7    Scanner scanner = new Scanner(System.in);
8 
9    String result = scanner.next();
10    assertEquals(input, result);
11 
12    System.setIn(stdin);
13    scanner.close();
14}

توجه کنید که ما از (…)System.setIn برای شبیه‌سازی برخی ورودی‌ها از کنسول استفاده کرده‌ایم.

API به نام ()nextLine

این متد صرفاً رشته‌ای که در خط جاری قرار دهد را بازمی‌گرداند:

1scanner.nextLine();

بدین ترتیب محتوای خط جاری را خوانده و آن را به جز کاراکتر جداکننده خط در انتها (که در این مورد کاراکتر خط جدید است) بازگشت می‌دهیم. اسکنر پس از خواندن محتوا موقعیت خود را در حالت خط بعدی قرار می‌دهد. نکته مهمی که نباید فراموش کنیم این است که API به نام ()nextLine، جداکننده خط را مصرف کرده و موقعیت اسکنر را به خط بعدی جابجا می‌کند. از این رو دفعه بعد که بخواهیم از اسکنر بخوانیم، از حالت خط بعدی می‌خوانیم.

API به نام ()nextInt

این متد توکن بعدی را از ورودی به صورت یک int اسکن می‌کند:

1scanner.nextInt();

این API توکن عدد صحیح ممکن بعدی را می‌خواند. در این مورد اگر توکن بعدی یک عدد صحیح باشد و پس از آن یک جداکننده قرار داشته باشد، ()nextInt جداکننده خط را مصرف نخواهد کرد. به جای آن، موقعیت اسکنر روی خود جداکننده خط قرار می‌گیرد. بنابراین اگر یک سری از عملیات داشته باشیم که عملیات نخست به صورت ()scanner.nextInt و پس از آن به صورت ()scanner.nextLine باشد، و به عنوان ورودی یک عدد صحیح ارائه کنیم، هر دو عملیات اجرا خواهند شد. nextInt() API عدد صحیح را مصرف می‌کند و nextLine() API جداکننده خط را مصرف می‌کند و اسکنر را در آغاز خط بعدی قرار می‌دهد.

اعتبارسنجی ورودی

اکنون به بررسی شیوه اعتبارسنجی ورودی با استفاده از اسکنر می‌پردازیم. در مثال زیر از متد ()hasNextInt در Scanner برای بررسی این که ورودی عددی صحیح است یا نه، استفاده می‌کنیم:

1@Test
2public void whenValidateInputUsingScanner_thenValidated() 
3  throws IOException {
4    String input = "2000";
5    InputStream stdin = System.in;
6    System.setIn(new ByteArrayInputStream(input.getBytes()));
7 
8    Scanner scanner = new Scanner(System.in);
9 
10    boolean isIntInput = scanner.hasNextInt();
11    assertTrue(isIntInput);
12 
13    System.setIn(stdin);
14    scanner.close();
15}

اسکن یک رشته

در این بخش به بررسی شیوه اسکن یک رشته با استفاده از Scanner می‌پردازیم:

1@Test
2public void whenScanString_thenCorrect() 
3  throws IOException {
4    String input = "Hello 1 F 3.5";
5    Scanner scanner = new Scanner(input);
6 
7    assertEquals("Hello", scanner.next());
8    assertEquals(1, scanner.nextInt());
9    assertEquals(15, scanner.nextInt(16));
10    assertEquals(3.5, scanner.nextDouble(), 0.00000001);
11 
12    scanner.close();
13}

نکته: متد nextInt(16)، توکن بعدی را به صورت یک مقدار صحیح هگزادسیمال می‌خواند.

یافتن الگو

اینک به بررسی شیوه یافتن یک الگو با استفاده از اسکنر می‌پردازیم. در مثال زیر، از ()findInLine برای یافتن یک توکن در کل ورودی که با الگوی ارائه شده مطابقت داشته باشد، استفاده می‌کنیم:

1@Test
2public void whenFindPatternUsingScanner_thenFound() throws IOException {
3    String expectedValue = "world";
4    FileInputStream inputStream = new FileInputStream("test.txt");
5    Scanner scanner = new Scanner(inputStream);
6 
7    String result = scanner.findInLine("wo..d");
8    assertEquals(expectedValue, result);
9 
10    scanner.close();
11}

همچنین می‌توانیم با استفاده از ()findWithinHorizon مانند مثال زیر، به دنبال الگو در یک دامنه خاص باشیم:

1@Test
2public void whenFindPatternInHorizon_thenFound() 
3  throws IOException {
4    String expectedValue = "world";
5    FileInputStream inputStream = new FileInputStream("test.txt");
6    Scanner scanner = new Scanner(inputStream);
7 
8    String result = scanner.findWithinHorizon("wo..d", 5);
9    assertNull(result);
10 
11    result = scanner.findWithinHorizon("wo..d", 100);
12    assertEquals(expectedValue, result);
13 
14    scanner.close();
15}

توجه کنید که افق جستجو صرفاً تعداد کاراکترهایی است که جستجو درون آن اجرا می‌شود.

رد کردن الگو

در این بخش با شیوه رد کردن یک الگو در اسکنر آشنا می‌شویم. ما می‌توانیم در زمان خواندن ورودی با استفاده از Scanner از توکن‌هایی که با الگوی خاصی مطابقت دارند، رد شویم. در مثال زیر، از توکن Hello با استفاده از متد ()skip در اسکنر رد می‌شویم:

1@Test
2public void whenSkipPatternUsingScanner_thenSkipped() 
3  throws IOException {
4    FileInputStream inputStream = new FileInputStream("test.txt");
5    Scanner scanner = new Scanner(inputStream);
6 
7    scanner.skip(".e.lo");
8 
9    assertEquals("world", scanner.next());
10 
11    scanner.close();
12}

تغییر جدا کننده اسکنر

در نهایت به بررسی شیوه تغییر «جداکننده» (Delimiter) در اسکنر می‌پردازیم. در مثال زیر جداکننده پیش‌فرض را به “o” عوض می‌کنیم:

1@Test
2public void whenChangeScannerDelimiter_thenChanged() 
3  throws IOException {
4    String expectedValue = "Hello world";
5    String[] splited = expectedValue.split("o");
6 
7    FileInputStream inputStream = new FileInputStream("test.txt");
8    Scanner scanner = new Scanner(inputStream);
9    scanner.useDelimiter("o");
10 
11    assertEquals(splited[0], scanner.next());
12    assertEquals(splited[1], scanner.next());
13    assertEquals(splited[2], scanner.next());
14 
15    scanner.close();
16}

همچنین می‌توانیم از چندین جداکننده استفاده کنیم. در مثال زیر از هر دو جداکننده کاما “,” و خط تیره “-“ برای اسکن کردن محتوای یک فایل که شامل عبارت John,Adam-Tom است، استفاده می‌کنیم:

1@Test
2public void whenReadWithScannerTwoDelimiters_thenCorrect() 
3  throws IOException {
4    Scanner scanner = new Scanner(new File("test.txt"));
5    scanner.useDelimiter(",|-");
6 
7    assertEquals("John", scanner.next());
8    assertEquals("Adam", scanner.next());
9    assertEquals("Tom", scanner.next());
10 
11    scanner.close();
12}

نکته: جداکننده پیش‌فرض اسکنر کاراکتر فاصله (whitespace) است.

سخن پایانی

در این راهنما به بررسی چندین مثال واقعی از کاربردهای اسکنر جاوا پرداختیم. بدین ترتیب با شیوه خواندن ورودی از فایل، کنسول و یا رشته با استفاده از اسکنر آشنا شدیم. همچنین شیوه یافتن و رد کردن الگوهای خاص را با استفاده از اسکنر مشاهده کردیم و در نهایت روش تغییر جداکننده را در اسکنر آموختیم. کدهای کامل این مقاله را می‌توانید در این رپیوی گیت‌هاب (+) ملاحظه کنید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
baeldung
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *