'분류 전체보기'에 해당되는 글 417건

  1. 2010.12.03 Intent에 의한 사진뷰어, 갤러리, 카메라 제어 1
  2. 2010.10.22 manifest-element 15
  3. 2010.10.13 C2DM
  4. 2010.10.13 [번역] 안드로이드 Android Cloud to Device Messaging(C2DM)
  5. 2010.08.17 OMA DRM에 대한 개요
  6. 2010.07.06 웹개발자를 위한 안드로이드 강좌-설치
  7. 2010.07.06 안드로이드 http connection UTF-->euc-kr 7
  8. 2010.06.25 안드로이드 하이브리드 앱 - 1. WebView로 로컬 파일(HTML) 로드하기 2
  9. 2010.06.15 Android Fundamental 중 Activity와 Task
  10. 2010.05.07 정규식
2010. 12. 3. 20:44

Intent에 의한 사진뷰어, 갤러리, 카메라 제어





Intent는 정말 보면 기존 어플들의 기능을 재사용할 수 있도록 해주는 고마운 기능인것 같습니다. 
사진보기, 갤러리, 카메라는 Intent를 활용하여서 제어를 할 수 있기 때문에 또다시 이런 기능을 또 만들지 않도록 할 수 있고 개발기간을 단축할 수 있으며, 사용자에게도 익숙한 UI 이기때문에 효율성인 측면에서 대단히 좋은 기능이 아닐 수 없습니다. 따라서 이 세가지 기능에 대해서 정리를 해보았습니다.

1. 갤러리 관련 제어
 - 내장되어 있는 갤러리를 호출하여 사진을 선택 후 내가 어떤 사진을 선택했는지 URI로 가지고 데이터를 설정한다. 
 
 - 갤러리 리스트뷰 호출 
Intent i = new Intent(Intent.ACTION_PICK);
i.setType(android.provider.MediaStore.Images.Media.CONTENT_TYPE);
i.setData(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); // images on the SD card.
// 결과를 리턴하는 Activity 호출 startActivityForResult(i, REQ_CODE_PICK_PICTURE);
 - 갤러리 리스트뷰에서 사진 데이터를 가져오는 방법
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQ_CODE_PICK_PICTURE) {
if (resultCode == Activity.RESULT_OK) { 
ImageView img = (ImageView)findViewById(R.id.image);
img.setImageURI(data.getData()); // 사진 선택한 사진URI로 연결하기 
}
}


2. 사진뷰어 호출
// 개별 이미지에 대한 URI 생성
// ex>uri = content://media/external/images/media/4  --> 4 = id
Uri uri = ContentUris.withAppendedId( Images.Media.EXTERNAL_CONTENT_URI, id);  // id값은 사진고유 ID
Intent intend = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intend);


3. 카메라 호출
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
2010. 10. 22. 13:50

manifest-element




<manifest>

syntax:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         
package="string"
         
android:sharedUserId="string"
         
android:sharedUserLabel="string resource"
         
android:versionCode="integer"
         
android:versionName="string"
         
android:installLocation=["auto" | "internalOnly" | "preferExternal"] >
    . . .
</manifest>

contained in:
none

must contain:
<application>
can contain:
<instrumentation>
<permission>
<permission-group>
<permission-tree>
<uses-configuration>
<uses-permission>

<uses-sdk>

description:
The root element of the AndroidManifest.xml file. It must contain an <application> element and specify xlmns:android and package attributes.
attributes:
xmlns:android
Defines the Android namespace. This attribute should always be set to "http://schemas.android.com/apk/res/android".
package
A full Java package name for the application. The name should be unique. The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers, and underscores ('_'). However, individual package name parts may only start with letters. For example, applications published by Google could have names in the form com.google.app.application_name.

The package name serves as a unique identifier for the application. It's also the default name for the application process (see the <application> element's process process attribute) and the default task affinity of an activity (see the <activity> element's taskAffinity attribute).

android:sharedUserId
The name of a Linux user ID that will be shared with other applications. By default, Android assigns each application its own unique user ID. However, if this attribute is set to the same value for two or more applications, they will all share the same ID — provided that they are also signed by the same certificate. Application with the same user ID can access each other's data and, if desired, run in the same process.
android:sharedUserLabel
A user-readable label for the shared user ID. The label must be set as a reference to a string resource; it cannot be a raw string.

This attribute was introduced in API Level 3. It is meaningful only if the sharedUserId attribute is also set.

android:versionCode
An internal version number. This number is used only to determine whether one version is more recent than another, with higher numbers indicating more recent versions. This is not the version number shown to users; that number is set by the versionName attribute.

The value must be set as an integer, such as "100". You can define it however you want, as long as each successive version has a higher number. For example, it could be a build number. Or you could translate a version number in "x.y" format to an integer by encoding the "x" and "y" separately in the lower and upper 16 bits. Or you could simply increase the number by one each time a new version is released.

android:versionName
The version number shown to users. This attribute can be set as a raw string or as a reference to a string resource. The string has no other purpose than to be displayed to users. The versionCode attribute holds the significant version number used internally.
android:installLocation
The default install location for the application.

The following keyword strings are accepted:

Value Description
"internalOnly" The application must be installed on the internal device storage only. If this is set, the application will never be installed on the external storage. If the internal storage is full, then the system will not install the application. This is also the default behavior if you do not define android:installLocation.
"auto" The application may be installed on the external storage, but the system will install the application on the internal storage by default. If the internal storage is full, then the system will install it on the external storage. Once installed, the user can move the application to either internal or external storage through the system settings.
"preferExternal" The application prefers to be installed on the external storage (SD card). There is no guarantee that the system will honor this request. The application might be installed on internal storage if the external media is unavailable or full, or if the application uses the forward-locking mechanism (not supported on external storage). Once installed, the user can move the application to either internal or external storage through the system settings.

Note: By default, your application will be installed on the internal storage and cannot be installed on the external storage unless you define this attribute to be either "auto" or "preferExternal".

When an application is installed on the external storage:

  • The .apk file is saved to the external storage, but any application data (such as databases) is still saved on the internal device memory.
  • The container in which the .apk file is saved is encrypted with a key that allows the application to operate only on the device that installed it. (A user cannot transfer the SD card to another device and use applications installed on the card.) Though, multiple SD cards can be used with the same device.
  • At the user's request, the application can be moved to the internal storage.

The user may also request to move an application from the internal storage to the external storage. However, the system will not allow the user to move the application to external storage if this attribute is set to internalOnly, which is the default setting.

Introduced in: API Level 8.

introduced in:
API Level 1 for all attributes, unless noted otherwise in the attribute description.

see also:
App Install Location
<application>
2010. 10. 13. 16:02

C2DM





C2DM (Cloud to Device Messaging) 은 인터넷에서 안드로이드 폰에 메시지를 보낼수 있는 기술이다.

인터넷에 최신 정보가 올라와 있는 데도 휴대폰이 서버에 접속해서 알아 보기 전 까지는
최신 정보가 올라와 있는 줄 모른다. 그 이전에는 일일이 휴대폰에서 특정 시간 간격으로
서버에 접속해 알아 보아야 했다. 이럴 경우 문제가 되는 것은 배터리 소모가 많고 네트웍
트래픽이 증가 한다는 문제점이 있다.

이를 위한 해결책으로 C2DM 이 나왔다.

이 기술을 사용하기 위해서는 안드로이드 2.2 가 설치된 폰에서
마켓에 등록된 앱을 사용해야 한다. 아직은 정식 릴리즈 되지 않았기
때문에 등록 신청한 후 시험해 볼 수 있다.

먼저 전체적인 그림을 보면 다음과 같은 구성 요소들이 있다.

1. 안드로이드 폰
2. 어플리케이션 서버
3. C2DM 서버

안드로이드 폰에서 푸시 기능을 사용하고 싶다면 다음과 같은 절차가 필요하다.

1. 안드로이드 폰에서 푸시 기능 활성화 하기
2. 어플리케이션 서버에서 C2DM 서버로 메시지 보내기
3. C2DM 서버에서 해당 안드로이드 폰으로 메시지 전달하기

안드로이드 폰 사용자들이 마켓에서 앱을 다운로드 받아 설치 할 때
앱이 C2DM 기능을 가지고 있다는 정보를 받고 이 기능을 사용할지 않을지를
선택 할 수 있다.

실제로 C2DM 을 사용하는 앱을 개발하는 절차를 알아보자

1. AndroidManifest.xml
   1.1. Permission
- RECEIVE
- C2D_MESSAGE
- INTERNET
   1.2. Receiver
1.2.1. intent filters
- RECEIVE
- REGISTRATION

2. C2DM 에 등록하기
   2.1. REGISTER 인텐트 생성 with sender and app
   2.2. startService

3. 등록 결과 처리하기

   단계 2 에서 REGISTER 인텐트를 날리면 등록 ID 값을 가진 인텐트를 받게 되는데
   이 인텐트를 받아 어플리케이션 서버에 내 등록 ID 를 전달하여야 한다.

4. 메시지 처리 하기

   등록이 성공하면 어플리케이션 서버는 언제든지 메시지를 보낼수 있는데
   메시지는 크기는 1024 바이트로 제한된다. 따라서 전체 데이타를 다 보내기 보다는
   어플리케이션에게 새로운 데이타가 있으니 접속해서 업데이트 하라는 메시지만
   보내야 한다.

어플리케이션 서버가 C2DM 서버에게 메시지를 보내기 위해서는 HTTP POST 를
https://android.apis.google.com/c2dm/send 를 사용하여 보내면 된다.

원문 http://joejeon.tistory.com/310
2010. 10. 13. 15:35

[번역] 안드로이드 Android Cloud to Device Messaging(C2DM)





Android Cloud to Device Messaging
[이 포스트는 이 기능을 구현하는데 기여한 Wei Huang 에 의해 작성되었습니다. — Tim Bray]


  새롭게 발표된 안드로이드 2.2 에서, 우리는 Android Cloud to Device Messaging (C2DM) 서비스를 추가하였습니다. 이 서비스는 개발자들이 서버와 모바일 어플리케이션간에 데이타를 쉽게 싱크할 수 있도록, 서버쪽 에서에서 안드로이드 폰 상의 어플리케이션으로 데이타를 손쉽게 전달할 수 있도록 도와줍니다.

 유용한 휴대폰 어플리케이션들은 대부분 사용자가 인터넷과 연결되도록 유지합니다. 이를 위해 전통적으로 많은 어플리케이션들은 주기적으로 데이터를 가져오기 위해 폴링 방식을 사용합니다. 예를들어 POP 이메일 클라이언트의 경우 15분 마다 이메일 서버와 연결되어 새로운 이메일을 가져오도록 구현될 수 있습니다. 이러한 폴링 방식은 비교적 구현하기가 용이하고, 대부분의 경우 잘 작동합니다. 하지만, 어떤한 주기로 폴링 작업을 수행할지 결정하는 것은 조금 애매한 구석이 있습니다. 폴링을 너무 자주하게 되면, 새로운 데이타가 없는데도 불구하고 불피요한 작업이 수행되며 서버와 네트워크에 부하를 줄 수 있습니다. 너무 드물게 폴링을 수행하면 어플리케이션이 갖고 있는 데이터가 전혀 갱신되지 않는 것 처럼 느껴질지도 모릅니다. 특히나 모바일 디바이스에서 효율적으로 폴링 작업을 수행하는 것은 중요한 문제입니다. 왜냐하면 폴링 작업은 귀중한 네트워크 밴드위스와 베터리를 소모시키기 때문입니다.

 폴링 방식을 사용하는 대신, 비동기적으로 클라이언트에 메세지를 푸쉬해주는 서버를 갖추는 것은 어플리케이션이 효율적으로 새로운 데이터를 전달 받을 수 있는 훨씬 좋은 선택이 될 수 있습니다. 하지만 훌륭한 푸쉬 솔루션을 구현하는 것은 어려운 일이며, 서버측과 특정한 연결을 유지하고 있어야 하는 오버헤드가 발생합니다. 특히 안드로이드폰과 같은 모바일 디바이스에서 이를 구현하는데는 네트워크 상태(고르지 못한 네트워크 커버리지, 무선망 상황이 좋지 않아 커넥션을 시도해도 타임아웃에 걸리고 마는 좀비 커넥션등) 에관한 고려가 필요하기 때문에, 교묘한 기술이 필요합니다. 

 G-메일, 주소록, 캘린더와 같은 안드로이드용 구글 어플리케이션은 데이터를 항상 최신으로 유지하기 위해 이미 푸시 방식을 사용하고 있습니다. 안드로이드 2.2 부터 C2DM 를 사용하면 서드파티 개발자들도 구글 어플리케이션과 동일한 서비스를 사용할 수 있습니다.

C2DM 에 대해서 몇 가지 기본적으로 알아야 하는 사항이 있습니다. 
  • 안드로이드 2.2 버전이 필요합니다. 
  • C2DM 은 '구글 서비스'를 사용합니다. 이 서비스는 안드로이드 마켓을 사용하는 모든 디바이스에 존재합니다.
  • C2DM 은 '구글 서비스' 를 위해 이미 존재하는 커넥션을 사용합니다.
  • C2DM 은 안드로이드 폰 상에서 사용자가 구글 계정으로 로그인 해야 사용이 가능합니다.
  • C2DM은 서드파티 서버가 간단한 메세지를 자신들의 어플리케이션으로 전달하는 것을 허용합니다.
  • C2DM 서비스는 대량의 컨텐츠를 푸쉬하도록 설계되지 않았습니다. 대신 특정 어플리케이션에게 새로운 데이타가 있음을 '쿡' 하고 알려 주고, 어플리케이션이 해당 서버에 접속해서 데이타를 다운로드 받을 수 있도록 하는데 사용되어야 합니다. 
  • 어플리케이션은 메세지를 받기 위해 작동중일 필요가 없습니다. 시스템은 전달해야할 데이타가 도착하는 경우에, 브로드캐스트 인텐트를 이용해 해당 어플리케이션을 깨울 것 입니다. 따라서, 어플리케이션은 적절하게 브로드캐스트 리시버와 Permission 을 설정해야 합니다.
  • 데이타 메세지를 전달 받기 위해 사용자 인터페이스가 필요하지는 않습니다. 물론 어플리케이션이 원한다면 알림창에 노티피케이션을 날릴 수도 있을 것 입니다.

C2DM API 를 사용하는 것은 쉽습니다. C2DM 은 아래와 같이 작동합니다.
  • C2DM 을 사용하기 위해 디바이스 상의 어플리케이션은 우선 구글에 등록해 Registration ID 를 발급 받아야 합니다. 해당 ID 를 자신의 서버에 전달해야 합니다. 
  • 만일 자신의 서버가 푸시하고 싶은 메세지가 있을 경우, 메세지를 HTTP 를 통해 구글의 C2DM 서버에 전달합니다. 
  • C2DM 서버는 메세지를 디바이스에 라우팅 하고, 디바이스는 브로드캐스트 인텐트를 어플리케이션에 전달 할 것 입니다. 
  • 타켓 어플리케이션은 브로드 캐스트 인텐트를 통해 깨어나고 메세지를 처리합니다. 
  • 어플리케이션은 사용자가 더이상 푸시 서비스를 받고싶지 않을 경우 등록을 취소할 수 있습니다. 
 거의 다 되었습니다. 개발자에게 필요한 것은 HTTP를 전달할 수 있는 서버와 Intent API 를 어떻게 사용해야하는지 알고 있는 안드로이드용 어플리케이션 뿐입니다. 아래는 간단한 예제 코드입니다.

// Use the Intent API to get a registration ID
// Registration ID is compartmentalized per app/device
Intent regIntent = new Intent(
        "com.google.android.c2dm.intent.REGISTER");
// Identify your app
regIntent.putExtra("app",
        PendingIntent.getBroadcast(this /* your activity */, 
            0, new Intent(), 0);
// Identify role account server will use to send
regIntent.putExtra("sender", emailOfSender);
// Start the registration process
startService(regIntent);

Registration ID 는 개발자의 어플리케이션으로 com.google.android.c2dm.intent. REGISTRATION 이라는 액션값을 갖는 브로드 캐스 인텐트를 통해 전달되어 집니다. 다음은 Registration ID 를 전달 받기위한 예제 코드 입니다.

// Registration ID received via an Intent
public void onReceive(Context context, Intent intent) {
  String action = intent.getAction();
  if (“com.google.android.c2dm.intent.REGISTRATION”.equals(action)) {
    handleRegistration(context, intent);
  }
}

public void handleRegistration(Context context, Intent intent) {
  String id = intent.getExtra(“registration_id”);
  if ((intent.getExtra(“error”) != null) {
    // Registration failed.  Try again later, with backoff.
  } else if (id != null) {
    // Send the registration ID to the app’s server.
    // Be sure to do this in a separate thread.
  }
}

 서버측을 살펴보면, 개발자의 서버는 C2DM 서버와 통신하기 위해 ClientLogin Auth 토큰을 가져야합니다. 토큰을 이용해서, 서버가 디바이스에 메세지를 푸시하고 싶을 때, 다음과 같은 인증된 HTTP Post 를 통해 메세지를 전달 할 수 있습니다. 
  • Authorization: GoogleLogin auth=<auth token>
  • Registration ID 와 키/벨류 쌍으로 이루어진 데이타, Google C2DM 서버에서 동일한 키값을 갖고 있는 오래된 메세지를 가로채기 위해 사용되는 'Collapse Key' 등몇 가지 옵셔널한 파라매터들을 포함하도록 인코딩된 URL.
 개발자가 C2DM 서비스를 사용하면, 골치아픈 모바일 데이타 커넥션을 직접 처리할 필요가 없으며, 사용자가 인터넷과 연결되어있는지 신경쓸 필요도 없습니다. (Airplane 모드와 같이). C2DM 은 서버 스토어에 메세지들을 보관하고, 디바이스가 온라인 상태로 될 때 해당 메세지를 전달합니다. 기본적으로 개발자는 견고한 푸시서비스를 위해 온갖 복잡하고 어려운 일들을 모두 구글에게 맡길 수 있습니다. 어플리케이션은 구글이 이미 구축하고 검증한 푸시 서비스의 이점을 취하고, 인터넷에 연결되어진 상태로 유지될 수 있습니다. 무엇보다도 좋은 것은 여러분이  배터리 소모에대해 비난을 받지 않아도 됩니다.

어떻게 C2DM 이 가능한 어플리케이션을 만들 수 있는 가에 관한 정보는 Code Lab 에 있으며, 서비스 일반 릴리즈가 다가올 수록 보다 다양한 정보가 공개될 것 입니다. 
2010. 8. 17. 17:08

OMA DRM에 대한 개요




DRM은 Digital Right Management의 약자로 한마디로 디지털 저작권 보호를 위한 컨텐츠 암호화 또는 이를 위한 방법을 의미한다.

 

OMA DRM이라고 하면 OMA는 Open Mobile Alliance의 약자로 모바일 기기에서의 컨텐츠 보호를 위하여 구성한 컨소시움 정도라고 생각하면 된다. 따라서 OMA에서는 모바일 기기에서의 저작권 보호를 위한 다양한 기술 스펙을 제공한다고 하면 대충 정리가 될 것 같다. OMA DRM은 OMA에서 제안하는 DRM 방식이라고 하면 될 것 같은데 특히, Mobile Phone을 위한 DRM 스펙이라고 보면 된다. 최근에 사용하는 Mobile Phone의 유료 컨텐츠에는 대부분 OMA DRM을 이용하여 암호화를 한다고 생각하면 된다.

우리가 많이 들어본 SKT의 멜론서비스, KTF의 도시락 서비스 등 유료화된 음악 서비스는 OMA DRM이 걸려있다.

 

보통 DRM을 위해서는 암호화시키는 방법이 제일이다. 사용자는 암호화된 데이터를 받고 이를 풀기 위해서는 특정 키를 이용해야만 한다.

 

OMA DRM에서 서비스로 제공되는 컨텐츠는 다음과 같이 크게 3가지 방식으로 구분된다.

 

1. Forward Lock

 

Forward Lock은 컨텐츠 자체를 보호한다기 보다는 컨텐츠를 서로 공유할 수 없게 하는 방법이다.

초기 핸드폰에서는 무선 서비스로 컨텐츠를 다운 받았는데 이러한 컨텐츠는 특별한 암호화가 이루어지지 않았지만 PC 또는 다른 핸드폰으로 이동시킬 수 없었다. 다른 장치로 이동할 수 없기 때문에 사용이 허가된 사람만이 사용할 수 있어서 저작권을 보호하게 된다.

 

 

 

2. Combined Delivery

 

Combined Delivery에서는 우리가 어떤 컨텐츠를 받는다면 이에는 컨텐츠(Contents)와 권리 객체(Rights Object)가 하나로 묶여서 암호화 되어 있다. 권리란 것은 보통 허가(Permission)나 제한(Constraint)에 대한 정보(즉 이 컨텐츠는 몇번 재생 가능하다, 몇일까지 재생 가능하다는 등의 정보)를 의미하는데, 권리 객체가 같이 묶여 있기 때문에 키만 있으면 권리의 내용에 따라 바로 사용이 가능하다. OMA에서는 Forward Lock과 마찬가지로 Combined Delivery에 의한 데이터는 다른 장치로 이동하지 못하도록 해야 한다고 되어 있다.

 

 

 

3. Sepearte Delivery

 

Seperate Delivery는 말 그대로 컨텐츠와 권리 객체가 분리되어 있음을 나타낸다. 이런 경우에 컨텐츠와 권리 객체는 각각 암호화 되어 있다. 암호화된 컨텐츠는 다른 장비로 이동시켜도 관계없다. 권리 객체가 없으면 실제 이동된 컨텐츠는 사용할 수 없기 때문이다. 권리 객체는 무선 서비스 등을 통해서 별도로 받을 수 있다. 권리 객체를 받게 되면 이동된 컨텐츠를 바로 사용하는 것이 가능하다.

 

 

 

왜 Combined Delivery와 Seperate Delivery가 구분되어야 하냐면 보통 컨텐츠의 권리가 만료되었을 때 Combined Delivery는 다시 모든 정보를 받아야만 사용이 가능하다. 그러나 Seperate Delivery는 권리 객체만 따로 받으면 사용 가능하다. 이는 사용자 입장에서 보면, 같은 컨텐츠를 사용하기 위해서 많은 데이터를 2-3번 받을 필요없다는 것이다. 데이터는 1번만 받고 권리만 만료되었을 때 받으면 된다.

 

마찬가지로 다른 사용자에게 이동식 메모리(SD 카드, T-Flash)로 빠르게 복사한 경우에도 다른 사용자는 권리를 받아서 재사용이 가능하다. (물론 다른 사용자가 권리를 받을 경우에는 사용에 대한 돈은 지불해야 한다. 돈을 내야 권리를 주기 때문이다.)


2010. 7. 6. 11:32

웹개발자를 위한 안드로이드 강좌-설치




안드로이드 SDK 설치 및 실행
eclipse 3.5.1 기준으로 설명함
JDK .5.0 기준
1. Java SDK 설치
http://java.sun.com/javase/downloads/index.jsp

2. 이클립스 설치
http://www.eclipse.org/downloads/

3. Android SDK 설치
http://developer.android.com/sdk
참고 디텍토리 위치에 한글 포함되면 안됨(중요)

4. 안드로이드 Eclipse 플러그인 설치(ADT)
         

 Eclipse 3.5 (Galileo)
 
  Help/Install New Software
  Add 버튼 클릭
  Name엔 적당히 Android PlugIn이라고 채우시고, Location에 https://dl-ssl.google.com/android/eclipse/ 넣음   
  OK를 누르고  리스트에 표시된 Developer Tools 라고 되어있는 체크박스를 체크한후 Next, Next, 약관 동의, Finish   
  위 URL이 안된다면 http://dl-ssl.google.com/android/eclipse/로도 시도해보세요. (https -> http)
저는 https를 실패하여 http로 접속하였음

5. 이클립스 안드로이드 SDK 설정

이클립스의 메뉴 Windows/Preference 실행
왼쪽 탭에서 Android 선택
Browse를 한후 SDK를 설치한 디렉토리 선택 (디렉토리 패스에 한글이 들어가 있으면 안됩니다.)
Apply후 OK

6. 안드로이드 버전별 다운로드

안드로이드 2.0 SDK 부터 새로 생긴 방식입니다. 각 버전별 에뮬레이터 및 SDK를 별도로 다운로드 받게 되어있습니다.
Window/Android SDK and AVD Manager 실행
Available 패키지에서 설치를 원하는 API 버전 선택
(현재 https로 시작되는 것은 에러가 나는 경우가 종종 있습니다. 이경우 http://로 시작하는 주소를 Add Site로 추가합니다.
Install Selected
설치가 모두 완료되었습니다.



 

2010. 7. 6. 10:10

안드로이드 http connection UTF-->euc-kr




 
package com.qnsolv.vanmsm.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Hashtable;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import com.qnsolv.vanmsm.common.SI;


/*
 * HttpUtil client = new HttpUtil(LOGIN_URL);  
client.AddParam("accountType", "GOOGLE");  
client.AddParam("source", "tboda-widgalytics-0.1");
client.AddParam("Email", _username);
client.AddParam("Passwd", _password);
client.AddParam("service", "analytics");
client.AddHeader("GData-Version", "2");
try {  
    client.Execute(RequestMethod.POST);
} catch (Exception e) {  
    e.printStackTrace(); 
}  
String response = client.getResponse();
 */
public class HttpUtil {
	private String defaultUrl="";//자신의 서버url
	private ArrayList params;
	private ArrayList headers;
	private String url;
	private int responseCode;
	private String message;
	private String response;
	public String METHOD_GET = "GET";
	public String METHOD_POST = "POST";
	public int networkTime=20000;
	public Hashtable getResponse() {
		return VanUtil.packetAnalyis(response);
	}
	public String getErrorMessage() {
		return message;
	}
	public int getResponseCode() {
		return responseCode;
	}

	public HttpUtil(String url)
	{
		this.url = defaultUrl+url;
		params = new ArrayList();
		headers = new ArrayList();
	}

	public void AddParam(String name, String value)
	{
		params.add(new BasicNameValuePair(name, value));
	}

	public void AddHeader(String name, String value)
	{
		headers.add(new BasicNameValuePair(name, value));
	}
	
	public void execute(String method) throws Exception
	{
		if (method.equals(METHOD_GET)) {
			String combinedParams = "";
			if (!params.isEmpty()) {
				combinedParams += "?";
				for (NameValuePair p : params)
				{
					String urlEncoderStr="";
					try {
						urlEncoderStr = URLEncoder.encode(p.getValue(),"euc-kr");
					} catch (Exception e) {
						// TODO: handle exception
					}
					String paramString = p.getName() + "=" + urlEncoderStr;
					if (combinedParams.length() > 1)
					{
						combinedParams += "&" + paramString;
					}
					else
					{
						combinedParams += paramString;
					}
				}
			}
			VanUtil.println("DEBUG",this.getClass().getName() + " :="+url + combinedParams);
			HttpGet requestGet = new HttpGet(url + combinedParams);
			// add headers
			requestGet.addHeader("Accept", "text/plain, text/html, text/*");
			requestGet.addHeader("Referer", "vw.qnsolv.com");
			requestGet.addHeader("Host", "vw.qnsolv.com:8080");
			requestGet.addHeader("Connection", "Keep-Alive");
			requestGet.addHeader("User-Agent", "");
			requestGet.addHeader("Content-Type", "text/html;charset=UTF8");
			executeRequest(requestGet, url);
		} else if (method.equals(METHOD_POST)) {
			HttpPost request = new HttpPost(url);

			request.addHeader("Accept", "text/plain, text/html, text");
			if (!params.isEmpty()) {
				request.setEntity(new UrlEncodedFormEntity(params, HTTP.ISO_8859_1));
			}
			executeRequest(request, url);
		}

	}

	private void executeRequest(HttpUriRequest request, String url)
	{

		HttpParams httpParameters = new BasicHttpParams();  
		int timeoutConnection = networkTime; 
		HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); 
		int timeoutSocket = networkTime; 
		HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); 
		
		
		HttpClient client = new DefaultHttpClient(httpParameters);

	 

		HttpResponse httpResponse;
		try {
			
			httpResponse = client.execute(request);
			responseCode = httpResponse.getStatusLine().getStatusCode();
			message = httpResponse.getStatusLine().getReasonPhrase();
			HttpEntity entity = httpResponse.getEntity();
			if (entity != null) {

				InputStream instream = entity.getContent();
				response = convertStreamToString(instream);
				Hashtable ht = VanUtil.packetAnalyis(response);
				// Closing the input stream will trigger connection release
				instream.close();
			}

		} catch (ClientProtocolException e) {
			client.getConnectionManager().shutdown();
			e.printStackTrace();
			response=SI.gI().getVanDefaultCode()+"00000100W99네트워크 연결 지연 \n( 네트워트 연결시간 "+(networkTime/1000)+" 초)   ";
		} catch (IOException e) {
			client.getConnectionManager().shutdown();
			e.printStackTrace();
			response=SI.gI().getVanDefaultCode()+"00000100W99네트워크 연결 지연 \n( 네트워트 연결시간 "+(networkTime/1000)+" 초)    ";
		}
	}

	private static String convertStreamToString(InputStream is) {

		StringBuilder sb = new StringBuilder();
		
		try{
			BufferedReader reader= new BufferedReader(new InputStreamReader(is,"EUC-KR"));
			String line = null;
			try {
				while ((line = reader.readLine()) != null) {
					sb.append(line + "\n");
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}catch(Exception e){
			
		}
		
		
		return sb.toString();

	}

}

2010. 6. 25. 12:51

안드로이드 하이브리드 앱 - 1. WebView로 로컬 파일(HTML) 로드하기





로컬 HTML(JavaScript)과 App 영역이 통신(함수호출)을 함으로써 간단한 하이브리드 앱을 만들어볼 수 있다.

1. HTML에서 App 함수 호출
   1) 멤버로 android.os.Handler 를 생성한다. 호출 시 thread 처리를 위해서 이용된다.
        private final Handler handler = new Handler();

   2) App과 Javascript간 Bridge 클래스를 생성하고, 호출될 함수를 implement 한다.
       (이 때 파리메터는 반드시 final로 선언)
       Javascript에서 호출시 별도의 Thread로 구동될 수 있도록 아래와 같이 구현한다.

          private class AndroidBridge {
            public void setMessage(final String arg) { // must be final
                handler.post(new Runnable() {
                    public void run() {
                        Log.d("HybridApp", "setMessage("+arg+")");
                        mTextView.setText(arg);
                    }
                });
            }
          }

   3) onCreate 함수에서 WebView에서 JavaScript를 Enable 하고, JavaScriptInterface로 Bridge 인스턴스를 등록한다.
        // 웹뷰에서 자바스크립트실행가능
        mWebView.getSettings().setJavaScriptEnabled(true);
        // Bridge 인스턴스 등록
        mWebView.addJavascriptInterface(new AndroidBridge(), "HybridApp");
 
    4) HTML 내에서 JavaScript에서 선언된 함수를 다음과 같이 호출 한다.
            window.<interfaceName>.<functionName>

  window.HybridApp.setMessage(msg);


2. App에서 HTML의 Javascript 함수 호출
   이부분은 간단하다....HTML에거 링크걸 때를 생각하면 되는데....
   그냥 버튼을 눌렀을 때 다음과 같이 호출하면 된다.
    mWebView.loadUrl("javascript:<함수명>('<arg>')");

    실제 구현은 다음과 같이 된다.
       mButton.setOnClickListener( new OnClickListener(){
        public void onClick(View view) {
            mWebView.loadUrl("javascript:setMessage('"+mEditText.getText()+"')");           
        }
       });

위의 방법으로 연결된 간단한 하이브리드 어플리케이션이다...





출처 : http://devian.tistory.com/159
2010. 6. 15. 14:05

Android Fundamental 중 Activity와 Task





출처 : [KANDROID]


Activity & Task
 하나의 activity는 다른 activity를 시작할 수 있고 다른 application의 activity도 시작할 수 있다. 예를 들어 임의위치의 street map을 display한다고 가정하자, 이런 작업을 하는 activity는 이미 제공된다. 따라서 당신의 activity에서 이 activity를 시작하기 위해 해야 할 일은 필요한 정보를 포함하는 intent object를 startActivity()에 파라메터로 전달하여 호출하는것 뿐이다. 이렇게 하면 street map viewer가 표시될것이다. 이 때 BACK버튼을 누르면 viewer를 시작한 당신의 activity가 다시 보여질 것이다.
 이는 사용자로 하여금 street map viewer가 당신의 application의 일부라고 느끼게 한다. 하지만 실제로는 그 activity는 다른 app의 다른 process상의 activity이다.
 안드로이드는 이처럼 사용자가 사용한 activity들을 task로 하여 그 정보를 유지한다. 관련된 activity는 group으로 stack에 저장된다.
 root activity는 task상의 첫번째 activity이고 top activity는 현재 화면에 보여지는 activity이다. activity가 다른 activity를 시작하면 그 새로운 activity가 stack에 push되고 그 activity가 top activity가 된다. 그리고 이전 activity는 stack에 남아 있는다. 이 상태에서 사용자가 BACK버튼을 누르면 이전 activity가 stack에서 POP되어 화면에 보여지게 되어 resume된다.
stack은 activity의 object(instance)를 가지고 있다. 따라서 같은 activity의 여러개의 instance가 가능하다. 같은 activity를 여러개 시작할수 있다는 의미이다.
 stack내의 activity는 stack이므로 재정렬되지 않는다. 순서는 그대로 유지되게 된다. 단지 PUSH, POP만 된다.
Task는 activity들의 stack이다. 따라서 task내의 activity에 어떤 값을 설정하는 방법은 없다. root activity만이 affinity(친밀도) set을 이용하여 read, set이 가능하다.
Task의 모든 activity들은 하나의 집합으로 background또는 foreground로 이동한다. 현재 Task가 4개의 activity를 가진다고 가정해보자. HOME 키를 누르면 application launcher로 이동한다. 이어서 새로운 application을 실행한다. 그러면 현재 task는 background로 가고 새로운 task의 root activity가 표시된다. 이어 사용자가 다시 HOME으로 갔다가 이전 application을 다시 선택한다면 그 task가 다시 앞으로 나온다. 이 때 BACK키를 누르면 root activity가 표시되지 않고 task상의 이전 activity가 표시된다.

      A1 -> A2 -> A3 -> A4 -> HOME -> B 1-> B2 -> HOME -> A4 -> BACK -> A3

task와 activity간의 결합과 동작에 대한 제어는 intent object의 flag 파라메터와 minifest의 <activity> element의 몇가지 속성으로 제어가 가능하다.

    flag -> FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_RESET_TASK_IF_NEEDED, FLAG_ACTIVITY_SINGLE_TOP
    <activity>'s attributes -> taskAffinity, launchMode, allowTaskReparenting, clearTaskOnLaunch, allowRetainTaskState, finishOnTaskLaunch

Affinityes and new Tasks
 기본적으로 하나의 application의 activity들은 각기 하나의 affinity를 갖는다. 그러나 각각의 affinity들은 <activity> element의 taskAffinity속성으로 affinity set을 이룰수 있다. 서로 다른 application의 activity들이 동일한 affinity를 공유할 수 있으며 한 application의 activity들이 서로 다른 affinity를 가질수 있다. affinity는 intent object에 FLAG_ACTIVITY_NEW_TASK로 activity를 적재할 때와 activity가 allowTaskReparenting속성을 true로 set하였을 때 시작된다.

FLAG_ACTIVITY_NEW_TASK 적용시
 앞서 기술한대로 기본적으로 activity는 startActivity()로 task안에 적재된다. caller와 동일한 stack에 push된다. 그러나 startActivity()가 FLAG_ACTIVITY_NEW_TASK 로 flag를 set하여 호출하면 시스템은 새로운 activity를 담기위한 task를 찾는다. 보통 새로운 task가 생성되지만 동일한 affinity를 갖는 task가 검색되면 그 태스크에 가서 달라붙는다.

allowTaskReparenting 적용시
 특정 activity가 allowTaskReparenting속성이 "true"이면, 시작된 task에서 동일한 affinity를 갖는 다른 task가 foreground로 올라올때 그 task로 activity가 이동될 수 있다. 예를 들면, 특정도시의 날씨를 보여주는 activity를 가지고 있는 travel application이 있다고 하자. travel application에 동일한 affinity를 갖는 다른 activity가 있고 reparenting이 가능하다. 이 상태에서 당신의 application의 activity가 travel application의 날씨 activity를 시작하면 날씨 activity는 당신의 task에 적재되게 된다. 그러나 이 때 travel application이 적재되게 되면 날씨 activity는 새로 시작된 travel application의 task에 재위치지정이 되고 화면에 표시되어진다.

travel application : Weather activity, ... -> allowTaskReparenting이 true이고 모두 동일 affinity를 갖는다.
your application : A, B, C, D activity

 launch travel application -> (1)start Weather activity -> HOME -> launch your application -> start A activity -> (2)start Weather activity -> HOME -> (3)travel application -> display Weather activity
  
(1) 시점에서 weather activity는 task1(travel app의 task)에 적재된다. (2)시점에서 weather activity는 task2(your app의 task)에 적재된다. (3)의 시점에서 travel app가 다시 시작될때 task2에 있던 weather activity가 task1으로 재지정되게 된다.
  
하나의 패키지(*.apk)에 여러 application이 정의되어 있다면 app단위로 각기 다른 affinity를 부여하는것이 좋다.

Launch Mode
 <activity> element에 lounchMode 속성을 조정하여 activity를 컨트롤할 수 있다. 

            standard, singleTop, singleTask, singleInstance

 위 4가지 모드는 4가지 관점에서 다르게 동작한다.
* 임의 Intent에 대해 어떤 task가 그 activity를 받을 것인가?
 standard, singleTop모드는 intent가 발생된 task에 push된다. flag를 FLAG_ACTIVITY_NEW_TASK로 설정해도 호출한 동일한 task내에 push된다. 위에 기술한 affinity & new task에 따라 다른 task가 선택될수 있다.
 singleTask및 singleInstance는 task를 정의하여 root activity로 적재되고 다른 task에 적재되지 않는다.
* 다중 instance activity가 가능한가?
standard, singleTop모드는 여러 task에 소속될수도 있고 한 task에 동일한 activity가 여러 instance가 적재될수도 있다. 
singleTask, singleInstance는 task내에서 오로지 한개의 instance만 적재된다. root activity만 가능하기 때문에 device내에서 한번에 하나의 Instance만 존재할 수 있다.
* Instance가 task내에서 다른 activity를 가질수 있는가?
 singleInstance는 task내에서 오직 하나의 instance만 가능하며, 만일 다른 activity를 시작하면 launchMode에 관계없이 새로운 task가 생성되어 적재된다.
 standard, singleTask, singleTop은 모두 multi instance가 가능하다. singleTask는 root activity로 생성되며 다른 activity를 task내에 적재가 가능하다. singleTop과 standard모드는 stack내에서 자유롭게 다른 activity를 생성가능하다.
* 특정 class의 새로운 instance가 새로운 intent를 다룰것인가?
 standard모드는 새로운 instance가 새로운 intent의 응답으로 생성된다. 각 instance는 오직 하나의 intent를 다룬다.
 singleTop : target-task의 stack에 top activity로 있다면 그 class의 instance가 intent를 재사용하여 처리한다. top activity가 아니면 재사용하지 않고 새로운 instance가 생성되어 intent를 처리하고 stack에 push된다.

예) A - B - C - D에서 D를 시작하려고 할 때  D가 singleTop이면 A - B - C - D 로된다.
     A - B - C - D에서 D를 시작하려고 할 때  D가 standard이면 A - B - C - D - D 로된다.
     B가 singleTop이나 standare이면 A - B - C - D - B 가 가능하다.
     

Clearing the stack
  기본적으로 사용자가 task를 오랫동안 사용하지 않으면 system은 task의 root activity만을 제외하고 모든 activity들을 clear한다. <activity>element의 몇가지 속성은 이를 조정할 수 있게 해준다.

alwaysRetainState 속성
  task의 root activity에 이 속성을 set하면 이 task는 오랜시가이 지나도 생존하게 된다.
clearTaskOnLaunch 속성
  task의 root activity에 이 속성을 set하면 task를 나가고 돌아올때 clear된다.
finishOnTaskLaunch
  clearTaskOnLaunch와 유사하나 이 속성은 하나의 activity에만 유효하다. root activity를 포함하여 현재 세션인 경우에만 살아있고 task를 떠나면 clear된다.

  stack에서 activity를 제거하는 다른 방법이 있다.
  intent object의 flag를 FLAG_ACTIVITY_CLEAR_TOP로 하고 이 intent를 처리할 activity가 target task에 이미 instance를 가지고 있다면 상위 activity들이 모두 clear되고 그 activity가 top activity가 된다.   launchMode가 "standard"라면 stack에서 마찬가지로 삭제되고 새로운 activity가 그 intent를 처리할 것이다.
  FLAG_ACTIVITY_NEW_TASK와 FLAG_ACTIVITY_CLEAR_TOP이 함께 사용되면 존재하는 activity가 새 task에 생성되어 intent를 처리한다.

Starting task
  activity는 intent filter중에 action filter로 android.intent.action.MAIN를 그리고 category filter로  android.intent.category.LAUNCHER로 entry point가 설정된다. 이런 설정은 icon과 label정보를 가지로 화면에 표시하고 task에 적재하고 적재후 언제든지 다시 돌아올수 있도록 해준다.
  사용자는 언제든 task를 떠날수 있고 다시 돌아올수 있다. singleTask와 singleInstance로 설정된 activity는 반드시 MAIN과 LAUNCHER를 filter로 적용해야 한다. 그러지 않으면 activity를 수행후 다른 화면으로 갔다가 다시 돌아올 수 있는 방법이 없게 된다.

  FLAG_ACTIVITY_NEW_TASK 는 activity하나가 새로운 task에 시작되고 HOME key를 눌렀을 경우 다시 복귀하기 위해 다른 방법이 있다. 
  외부 task에서 notification manager같은 entity에서 항상 activity들을 시작할 수 있다. 이런 방식으로 외부에서 activity를 invoke할 수 있다면 사용자가 다른 방법으로 그 task를 시작할 수 있음을 유의해야 한다. 이런 경우 그 activity로 복귀하기를 원하지 않는다면 finishOnTaskLaunch를 사용하면 된다.
2010. 5. 7. 17:31

정규식




정규식, 정규표현식 다 같은말이다.

어느 프로그래밍언어든 정규식, 정규표현식 을 다루는것은 비슷하다.

1. 개념잡기

일반화 시킨 표현. 이것을 정규표현이라고 요약할 수 있을 것 같다.
다음의 과정을 너무 쉽다 생각말고 따라오길 바란다.

 - 감잡기

"12354" -> 숫자
"asdfasf" -> 알파벳
두 가지의 간단정규표현을 만들었다. 실생활의 보기와 비추어보자.
"길이가 3인 이름!"
위의 표현은 길이를 표시하는 방법이 없다. 조금 더 발전시켜서 "알파벳{3}"이런식
으로 길이를 표현할 수 있도록 한다. 그리고, "알파벳"란 것도 너무 길다 "알"
이라고 한 글자로 표현한다. 그러면 "길이가 3인 이름"은
 "알{3}"으로 표시가 가능하다.
길이가 10인 숫자는 "수{10}"
"길이가 1인 알파벳이 나오고 그 다음에 길이가 3인 숫자가 나오는 문자열"! -> 
"알{1}수{3}"얼핏이나마 감이 올 것이다.
"첫 글자는A, 그 다음은 아무 알파벳 5글자" -> "A알{5}"

 - 조금 더

아이디는 대개 첫 글자는 영문이고 두 번째부터는 영문이나 숫자가 온다. 이것을 
표현하기 위해선 이것 들 중에 하나란 의미를 갖는 새로운 표현이 필요하다.
"a,b,c,d 중에 하나" -> [abcd]
응용하면, 
"알파벳이나, 숫자중 하나" -> [알수]
"[" 안에 있는 문자들의 순서는 의미가 없으며, 그 표현은 (클래스라고 한다.)  
결국 한 글자를 말한다.
위에서 말한 "첫 글자는 영문, 두 번째 부터는 영문이나 숫자가 11자"를 
표현하면, "알[알수]{11}".
그런데, 실제로 모든 아이디가 12자인 것은 아니다, 대개 4자부터 12자를 지원한다. 
새로운 표현이 등장한다. "몇 자부터 몇 자"
"A가 3글자부터 12자" -> "A{3,12}"
"알파벳이나 숫자가 1자부터 100자" -> "[알수]{1,100}"
이제 아이디를 다시 정의하자. 
"첫 글자는 영문, 영문이나 숫자가 3자부터 11자" -> "알[알수]{3,11}"

2. 표현식

지금 까지의 규칙에서 설명한 용어를 실제 정규표현에서 사용하는 표현으로 바꾸고, 
다른 세부적인 옵션에 대해 알아보자.

\ : 다음의 글자가 특별한 문자임을 나타낸다. 때론, 그 다음 문자 자체를 의미하기
도 한다. 
보기를 들면, "\n"은 문자"\"과 문자"n" 두 글자와 매치되는 것을 의미하는 것이 아
닌, 
새줄(New Line)을 의미하며, "\\"은 첫 "\" 다음 문자인 "\" 자체를 의미한다. 
즉, "\\"은 
"\"과 매칭된다. 

^ : 입력문자열의 맨 처음을 의미한다. (맨 첫 글자가 아니라, 맨 처음이란 문맥적 의
미를 
말한다. 아주 중요하다) 기본적으로 정규표현은 입력 문자열의 한 줄에만 적용된다. 
하지만, 옵션에 따라 여러줄에 적용할 수도 있다. 그럴 경우에는 "^"는  "\n" 
나 "\r" 
다음의 위치를 의미한다.

$ : "^"는 반대로 입력 문자열의 맨 끝을 의미한다. 역시 여러줄에 정규표현이 적용
될 
경우에는 "\n"이나 "\r"의 앞의 위치를 의미한다.

* : 이 문자 앞의 표현이 0번내지 무한번 반복될 수 있음을 말한다. 
보기를 들면, /a*/은 "a", "", "aaaa", "aaaaa"와 매칭된다. 
(0번이상은 없어도 된다는 것을 의미한다.)

+ : *와 같지만, 0번이상이 아니라 1번이상이라는 점을 제외하곤 /*/와 같다.

? : 앞의 표현이 0번 또는 1번. /do(es)?/는 "do", "does"와 매칭된다.

{n} : 앞의 표현이 n은 음수가 아닌 정수이어야 하며, 앞의 표현이 
n번 매치되는 것을 말한다. 

{n,} : 앞의 표현이 n은 음수가 아닌 정수이어야 하며, n번 이상 
매치되는 것을 말한다.

{n,m} : 앞의 표현이 n번 이상 부터 m번 이하까지 매칭되는 것을 
말하며, /*/는 /{0,}/과 같으며, /+/는 /{1,}/과 /?/는 /{0,1}/으로 
표현 가능하다.

. : "\n"을 제외한 한 글자를 뜻한다. 만일 모든 글자를 표현하고 
싶다면("\n"마저도 합친) /[.\n]/을 사용하면 된다.

x|y : x 또는 y와 매칭된다. 보기를 들면, /z|food/는 "z" 또는 
"food"와 매칭된다. /(z|f)ood/는 "zood" 또는 "food"와 매칭된다. 
(참고로 괄호는 묶어준 것 이상의 의미가 있다.)

(패턴) : 해당 패턴과 매칭시키고, 그 부분을 특정 변수에 담는다. 
그 변수 이름은 JScript는 $0~$9까지의 변수에 저장이 되고(Perl과 같다.), 
VBScript에서는 SubMatches 컬렉션에 저장된다. 
괄호기호 자체와 매치시키고 싶다면? /\(/와 /\)/를 사용한다.

(?:패턴) : 해당 패턴과 매칭은 시키지만, 그 부분을 특정 변수에 
담지 않는다. 왜 이게 필요할까?
위의 보기에서 /(z|f)ood/는 "zood" 또는 "food"와 매칭된다고 했는데, 
단순히 매칭의 목적으로 사용했지만, "zood"의 경우 "z"가 $0 이란 
변수에 저장이 되고 말았다. 이러한 것을 막기 위해서 사용하는 것이
 (?:패턴)이다.

(?=패턴) : (?:패턴)과 동일하지만, 패턴과 일치한 부분이후부터 
다음 매치가 일어나지 않고 패턴 앞부터 다시 매칭이 진행된다. 
즉, 룩업(lookup, lookahead)을 할 뿐이다. /Windows (?=95|98|NT|2000)/ 은 
"Windows 2000"의 "Windows" 부분과 매칭이 되며 다음 매칭은 
"2000" 다음 부터가 아닌 "Windows" 다음 부터 진행이 된다.

(?!패턴) : (?=패턴)과 반대다. /Windows (?=95|98|NT|2000)/ 은 
"Windows 3.1"의 "Windows" 부분과 매칭이 된다.

[xyz] : "["안에 있는 표현중 하나를 의미한다.

[^xyz] :  "["안에 있는 표현을 제외한 것중 하나를 의미한다. 
"[^abc]"는 "plain"의 "p"때문에 매칭된다.

[a-z] : "a"부터 "z" 까지의 문자중 하나

[^a-z] : "a"부터 "z" 까지의 문자를 제외한 하나

\b : 단어의 경계(단어와 공백, "\n", "\r"의 사이)와 매칭된다. 
보기를 들면, "er\b"는 "never"와는 매칭되지만, "verb"와는 매칭되지 않는다.

\B : 단어의 경계가 아닌 것과 매칭된다. "er\B"는 "verb"와는 
매칭되지만, "never"와는 매칭되지 않는다.

\cx : Ctrl+x 키와 매칭된다. "\cc"는 Ctrl+C와 매칭된다. x의 범위는 
[a-zA-Z]이며, 만일 이 이외의 문자를 사용한다면 "\c"는 "c"와 동일하다.

\d : [0-9]와 같다.

\D : [^0-9]와 같다. 참고로 대문자는 소문자의 반대 의미를 갖는다.

\f : 폼피드(form-feed) 문자를 의미하며, "\x0c"와 "\cL"과 동일하다.

\n : 새 줄(newline)를 의미하며, "\x0a"와 "\cJ"와 동일하다.

\r : 캐리지 리턴(carriage return)을 의미하며, "\x0d"와 "\cM"과 동일하다.

\t : 탭. "\x09", "\cI"과 동일

\v : 버티컬 탭. "\x0b", "\cK"과 동일

\s : 화이트스페이스를 의미한다. 화이트스페이스란 공백, 탭, 폼피드, 
캐리지리턴등을 의미한다. [ \f\n\r\t\v]과 동일("\f"앞에 공백이 있다. 주의!)

\S : "[^ \f\n\r\t\v]"

\w : "_"를 포함한 일반적인 단어에 사용되는 문자를 말한다. 
"[A-Za-z0-9_]" 과 동일

\W : "[^A-Za-z0-9_]"

\xn : n은 2자리 16진수이며, 해당 16진수 코드와 매칭된다. "\x412"는 16진수 
41은 "A"이기 때문에 "A2"와 매칭된다.

\num : 캡쳐한 매칭을 가리킨다(백레퍼런스, backreference). 
"(.)\1"은 연속된 두개의 문자열을 의미한다.
\n : "\1"은 위에서 캡쳐한 매칭(backreference)를 가리킨다고 했는데, 
만일 이 패턴앞에 어떠한 n개의 캡쳐한 표현이 있다면 백레퍼런스이지만, 
그렇지 않은 경우에는 8진수로 간주하여 해당 코드의 문자와 매칭된다.

\un : n은 4자리 UNICODE 이다. "\u00A9"은 copyright 심볼인 "ⓒ"와 매칭된다.


greedy, non-greedy

? : 앞에서 설명했는데, 왜 또? 라고 생각할 것이다. 
?은 문맥에 따라 특별한 의미를 갖는다.
패턴 "o*"는 "foooood"와 매칭된다. 당연하다! 하지만, "f"앞의 "o"와 
매칭되는 것이 아니다!! "ooooo"와 매칭된 것이다. 즉, 기본으로 
정규표현 매칭은 가장 큰 범위를 선택한다. 이것을 greedy하다고 한다.
하지만, 때론 작은 범위에 매칭시킬 필요가 있을 경우가 있다. 
(이의 적절한 보기는 잠시 후에 나온다.) "o*?"가 방금 말한 
non-greedy 매칭이다.
수량관련 문자인 "*", "+", "?", "{n}", "{n,}", "{n,m}" 다음에 "?"가 
나오면 non-greedy 매칭이된다.
잠시, 위에서 "o*?"가 "o"와 매칭된다고 했는데 이상하게 생각한 분이 
있었을 것이다. 맞다. "o*?"는 ""와 매칭되었다. "*"는 0개이상임을 
잊어선 안된다. "o+?"가 "o"와 매칭된다.

4. 보기

 - 웹 주소 

"
http://msdn.microsoft.com:80/scripting/default.htm"
위의 주소를 표현할 수 있는 정규표현은 아래와 같다.
/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/
$1 : http
$2 : msdn.microsoft.com
$3 : 80
$4 : /scripting/default.htm

 - 중복된 단어를 하나로 

중복된 영어단어를 하나로 합치기 위해선, 우선 단어를 찾아야한다. 
그리고 단어는 앞 뒤가 단어의 경계이어야한다. (말이 참 이상하지만..) 
따라서, 아래와 같은 1차 정규표현을 얻을 수 있다.

/\b([a-z]+)\b/

연속해서 동일한 두개의 단어... 앞에서 캡쳐한 표현을 다시 활용하면 된다. 
그리고, 단어와 단어 사이엔 화이트스페이스가 있다.

/\b([a-z]+)\s+\1\b/

 - HTML 태그 제거

HTML문서에서 태그를 제거한 문서를 추출하고자 한다. 
태그는 "<"와 ">"로 감싸여 있다.

/<.*>.*</.*>/

그런데, 위의 정규표현을 HTML문서에 적용하여 해당 패턴을 "", 
빈문자열로 바꾸면 문서는 빈 문서가 되고 만다.

<html>
<title>...</title>
<body>
<font>.... </font>
...
</body>
greedy한 매칭이 기본값이라고 위에서 언급을 했다. 따라서, 
위의 HTML 문서를 보면, <html>....</body>로 생각할 수 있다. 
따라서, 문서 전체가 사라지는 것이다. 이것을 막기 위해선 "*"뒤에 "?"를 
추가하면 된다.                            

/<.*?>.*?</.*?>/

아직 끝나지 않았다. :)

좀더 정제를 한다면, 올바른 HTML 문서는 <태그명>과 </태그명>이 
서로 일치한다. 이것도 적용한다면, 

/<.(*?)>.(*?)</\1>/

위의 $1에 해당되는 부분을 좀 더 생각해보면, ">"를 제외한 문자로 
볼 수 있다. 따라서 최종적으로 아래와 같이 정리된다.

/<(\w+)[^>]*?>(.*?)</\1>/

 - URL

/(?:^|")(http|ftp|mailto):(?://)?(\w+(?:[\.:@]\w+)*?)(?:/|@)([^"\?]*?)(?:\?
([^\?"]*?))?(?:$|")/

 - float 상수

/^(((+|-)?\d+(\.\d*)?)|((+|-)?(\d*\.)?\d+))$/  -1.1 1.1 .9 .8

 

정규식 구문

정규식은 일반 문자(예: a에서 z)와 메타문자 로 알려진 특수 문자로 구성된 텍스트 패턴입니다. 패턴은 텍스트 본문을 검색할 때 일치하는 문자열을 하나 이상 설명합니다. 정규식은 검색되는 문자열과 일치하는 문자 패턴을 찾는 템플릿의 역할을 합니다.

일반적으로 볼 수 있는 몇 가지 정규식 예는 다음과 같습니다.

JScript VBScript 검색
/^\[ \t]*$/ "^\[ \t]*$" 빈 줄을 찾습니다.
/\d{2}-\d{5}/ "\d{2}-\d{5}" 2자리, 하이픈 및 5자리로 구성된 ID 번호를 찾습니다.
/<(.*)>.*<\/\1>/ "<(.*)>.*<\/\1>" HTML 태그를 찾습니다.

아래 표는 정규식 컨텍스트에 사용되는 모든 메타문자와 메타문자의 동작을 보여줍니다.

문자 설명
\ 그 다음 문자를 특수 문자, 리터럴, 역참조, 또는 8진수 이스케이프로 표시합니다. 예를 들어, "n"은 문자 "n"을 찾고 "\n"은 줄 바꿈 문자를 찾습니다. "\\" 시퀀스는 "\"를 찾고 "\("는 "("를 찾습니다.
^ 입력 문자열의 시작 위치를 찾습니다. Multiline 속성이 설정되어 있으면 ^는 '\n' 또는 '\r'앞의 위치를 찾습니다.
$ 입력 문자열의 끝 위치를 찾습니다. Multiline 속성이 설정되어 있으면 $는 '\n' 또는 'r'뒤의 위치를 찾습니다.
* 부분식의 선행 문자를 0개 이상 찾습니다. 예를 들어, "zo*"는 "z", "zoo" 등입니다. *는 {0,}와 같습니다.
+ 부분식의 선행 문자를 한 개 이상 찾습니다. 예를 들어, "zo+"는 "zo", "zoo" 등이지만 "z"는 아닙니다. +는 {1,}와 같습니다.
? 부분식의 선행 문자를 0개 또는 한 개 찾습니다. 예를 들어, "do(es)?"는 "do" 또는 "does"의 "do"를 찾습니다. ?는 {0,1}과 같습니다.
{ n } n 은 음이 아닌 정수입니다. 정확히 n 개 찾습니다. 예를 들어, "o{2}"는 "Bob"의 "o"는 찾지 않지만 "food"의 o 두 개는 찾습니다.
{ n ,} n 은 음이 아닌 정수입니다. 정확히 n 개 찾습니다. 예를 들어, "o{2}"는 "Bob"의 "o"는 찾지 않지만 "foooood"의 모든 o는 찾습니다. "o{1,}"는 "o+"와 같고, "o{0,}"는 "o*"와 같습니다.
{ n , m } m n 은 음이 아닌 정수입니다. 여기서 m n 보다 크거나 같습니다. 최소 n 개, 최대 m 개 찾습니다. 예를 들어, "o{1,3}"은 "fooooood"의 처음 세 개의 o를 찾습니다. "o{0,1}"은 "o?"와 같습니다. 쉼표와 숫자 사이에는 공백을 넣을 수 없습니다.
? 이 문자가 다른 한정 부호(*, +, ?, { n }, { n ,}, { n , m })의 바로 뒤에 나올 경우 일치 패턴은 제한적입니다. 기본값인 무제한 패턴은 가능한 많은 문자열을 찾는 데 반해 제한적인 패턴은 가능한 적은 문자열을 찾습니다. 예를 들어, "oooo" 문자열에서 "o+?"는 "o" 한 개만 찾고, "o+"는 모든 "o"를 찾습니다.
. "\n"을 제외한 모든 단일 문자를 찾습니다. "\n"을 포함한 모든 문자를 찾으려면 '[.\n]' 패턴을 사용하십시오.
( pattern ) pattern 을 찾아 검색한 문자열을 캡처합니다. 캡처한 문자열은 VBScript의 경우 SubMatches 컬렉션, Jscript의 경우 $0 ... $9 속성을 이용하여 결과로 나오는 Matches 컬렉션에서 추출할 수 있습니다. 괄호 문자인 ( )를 찾으려면 "\(" 또는 "\)"를 사용하십시오.
(?: pattern ) pattern 을 찾지만 검색한 문자열을 캡처하지 않습니다. 즉, 검색한 문자열을 나중에 사용할 수 있도록 저장하지 않는 비캡처 검색입니다. 이것은 패턴의 일부를 "or" 문자(|)로 묶을 때 유용합니다. 예를 들어, 'industr(?:y|ies)는 'industry|industries'보다 더 경제적인 식입니다.
(?= pattern ) 포함 예상 검색은 pattern 과 일치하는 문자열이 시작하는 위치에서 검색할 문자열을 찾습니다. 이것은 검색한 문자열을 나중에 사용할 수 있도록 캡처하지 않는 비캡처 검색입니다. 예를 들어, "Windows(?=95|98|NT|2000)"는 "Windows 2000"의 "Windows"는 찾지만 "Windows 3.1"의 "Windows"는 찾지 않습니다. 예상 검색은 검색할 문자열을 찾은 후 예상 검색 문자열을 구성하는 문자 다음부터가 아니라 마지막으로 검색한 문자열 바로 다음부터 찾기 시작합니다.
(?! pattern ) 제외 예상 검색은 pattern 과 일치하지 않는 문자열이 시작하는 위치에서 검색할 문자열을 찾습니다. 이것은 검색한 문자열을 나중에 사용할 수 있도록 캡처하지 않는 비캡처 검색입니다. 예를 들어, "Windows(?!95|98|NT|2000)"는 "Windows 3.1"의 "Windows"는 찾지만 "Windows 2000"의 "Windows"는 찾지 않습니다. 예상 검색은 검색할 문자열을 찾은 후 예상 검색 문자열을 구성하는 문자 다음부터가 아니라 마지막으로 검색한 문자열 바로 다음부터 찾기 시작합니다.
x | y x 또는 y 를 찾습니다. 예를 들어, "z|food"는 "z" 또는 "food"를 찾습니다. "(z|f)ood"는 "zood" 또는 "food"를 찾습니다.
[ xyz ] 문자 집합입니다. 괄호 안의 문자 중 하나를 찾습니다. 예를 들어, "[abc]"는 "plain"의 "a"를 찾습니다.
[^ xyz ] 제외 문자 집합입니다. 괄호 밖의 문자 중 하나를 찾습니다. 예를 들어, "[^abc]"는 "plain"의 "p"를 찾습니다.
[ a-z ] 문자 범위입니다. 지정한 범위 안의 문자를 찾습니다. 예를 들어, "[a-z]"는 "a"부터 "z" 사이의 모든 소문자를 찾습니다.
[^ a-z ] 제외 문자 범위입니다. 지정된 범위 밖의 문자를 찾습니다. 예를 들어, "[^a-z]"는 "a"부터 "z" 사이에 없는 모든 문자를 찾습니다.
\b 단어의 경계, 즉 단어와 공백 사이의 위치를 찾습니다. 예를 들어, "er\b"는 "never"의 "er"는 찾지만 "verb"의 "er"는 찾지 않습니다.
\B 단어의 비경계를 찾습니다. "er\B"는 "verb"의 "er"는 찾지만 "never"의 "er"는 찾지 않습니다.
\c x X 가 나타내는 제어 문자를 찾습니다. 예를 들어, \cM은 Control-M 즉, 캐리지 리턴 문자를 찾습니다. x 값은 A-Z 또는 a-z의 범위 안에 있어야 합니다. 그렇지 않으면 c는 리터럴 "c" 문자로 간주됩니다.
\d 숫자 문자를 찾습니다. [0-9]와 같습니다.
\D 비숫자 문자를 찾습니다. [^0-9]와 같습니다.
\f 폼피드 문자를 찾습니다. \x0c와 \cL과 같습니다.
\n 줄 바꿈 문자를 찾습니다. \x0a와 \cJ와 같습니다.
\r 캐리지 리턴 문자를 찾습니다. \x0d와 \cM과 같습니다.
\s 공백, 탭, 폼피드 등의 공백을 찾습니다. "[ \f\n\r\t\v]"와 같습니다.
\S 공백이 아닌 문자를 찾습니다. "[^ \f\n\r\t\v]"와 같습니다.
\t 탭 문자를 찾습니다. \x09와 \cI와 같습니다.
\v 수직 탭 문자를 찾습니다. \x0b와 \cK와 같습니다.
\w 밑줄을 포함한 모든 단어 문자를 찾습니다. "[A-Za-z0-9_]"와 같습니다.
\W 모든 비단어 문자를 찾습니다. "[^A-Za-z0-9_]"와 같습니다.
\x n n 을 찾습니다. 여기서 n 은 16진수 이스케이프 값입니다. 16진수 이스케이프 값은 정확히 두 자리여야 합니다. 예를 들어, '\x41'은 "A"를 찾고 '\x041'은 '\x04'와 "1"과 같습니다. 정규식에서 ASCII 코드를 사용할 수 있습니다.
\ num num 을 찾습니다. 여기서 num 은 양의 정수입니다. 캡처한 문자열에 대한 역참조입니다. 예를 들어, '(.)\1'은 연속적으로 나오는 동일한 문자 두 개를 찾습니다.
\ n 8진수 이스케이프 값이나 역참조를 나타냅니다. \ n 앞에 최소한 n개의 캡처된 부분식이 나왔다면 n 은 역참조입니다. 그렇지 않은 경우 n 이 0에서 7 사이의 8진수이면 n 은 8진수 이스케이프 값입니다.
\ nm 8진수 이스케이프 값이나 역참조를 나타냅니다. \ nm 앞에 최소한 nm개의 캡처된 부분식이 나왔다면 nm 은 역참조입니다. \ nm 앞에 최소한 n개의 캡처가 나왔다면 n 은 역참조이고 뒤에는 리터럴 m이 옵니다. 이 두 경우가 아닐 때 n과 m이 0에서 7 사이의 8진수이면 \ nm 은 8진수 이스케이프 값 nm을 찾습니다.
\ nml n 이 0에서 3 사이의 8진수이고 m l 이 0에서 7 사이의 8진수면 8진수 이스케이프 값 nml 을 찾습니다.
\u n n 은 4 자리의 16진수로 표현된 유니코드 문자입니다. 예를 들어, \u00A9는 저작권 기호(©)를 찾습니다.

 

 

--------------------------------------------------------------------------------
Visual Basic Scripting Edition에서 정규 표현식 기능 이용하기 
--------------------------------------------------------------------------------

정규 표현식이란 무엇인가요?
정규 표현식이란 무엇일까요? 정규 표현식은 복잡한 패턴 매칭 기능과 텍스트형 검색-대체 알고리즘을 개발할 수 있는 툴을 제공합니다. Perl, egrep, awk, 또는 sed 개발자에게 정규 표현식이 무엇이냐고 물어보면, 정규 표현식은 텍스트와 데이터를 조작할 때 사용할 수 있는 가장 강력한 유틸리티라고 대답할 것입니다. 개발자는 패턴을 만들어 특정 문자열을 매치키시킴으로써 데이터를 검색하거나 추출하거나 교체하는 일을 완벽하게 제어할 수 있습니다. 간단히 말해서, 정규 표현식을 정복하면 데이터도 정복할 수 있는 것입니다. 

여기서는, VBScript 정규 표현식과 관련된 모든 개체를 설명하고, 일반적인 정규 표현식 패턴을 간략하게 살펴보고, 실제 코드로 정규 표현식을 사용하는 예를 들어보도록 합시다. 

VBScript RegExp 개체
VBScript 5.0 버전은 정규 표현식을 하나의 개체로서 제공합니다. VBScript RegExp 개체는 설계 면에서 JScript의 RegExp 및 String 개체와 비슷하고, 구문 면에서는 Visual Basic과 일치합니다. 먼저, VBScipt RegExp 개체의 속성과 메소드에 관해 알아봅시다. VBScript RegExp 개체는 사용자에게 세 개의 속성과 세 개의 메소드를 제공합니다. 

속성  메소드  
Pattern  Test(검색-문자열)  
IgnoreCase  Replace (검색-문자열, 대체-문자열)  
Global  Execute (검색-문자열  

Pattern - 정규 표현식을 정의하는 데 사용되는 문자열. 이 속성은 정규 표현식 개체를 사용하기 전에 먼저 설정해야 합니다. Pattern에 관한 내용은 아래에 자세히 설명되어 있습니다. 
IgnoreCase - 문자열 안에서 일치하는 문자가 발생할 모든 가능성에 대해 정규 표현식을 테스트해야 하는지를 나타내는 부울 논리 속성입니다. IgnoreCase의 기본 설정 값은 False입니다. 
Global - 문자열 안에서 일치하는 문자가 발생할 모든 가능성에 대해 정규 표현식을 테스트해야 하는지 여부를 나타내는 읽기 전용 부울 논리 속성입니다. Global의 기본 설정 값은 False입니다. 
Test (문자열) - Test 메소드는 문자열을 매개 변수로 받아 그 문자열이 정규 표현식에 일치하면 True를 반환하고 그렇지 않으면 False를 반환합니다. 
Replace (검색-문자열, 대체-문자열) - Replace 메소드는 두 개의 문자열을 매개 변수로 받습니다. 검색-문자열 안에 정규 표현식과 일치하는 문자열이 있으면, 그 문자열을 대체-문자열로 바꾸고, 바뀐 새로운 문자열을 반환합니다. 만일 일치하는 문자열이 없으면, 원래의 검색-문자열을 반환합니다. 
Execute (검색-문자열) - Execute 메소드는 Matches 컬렉션 개체를 반환하는 점만 제외하면 Replace 메소드의 작동과 비슷합니다. Matches 컬렉션 개체에는 정규 표현식에 일치하는 각 문자열에 대한 Match 개체가 들어 있습니다. 이 메소드는 원래의 문자열을 변경하지 않습니다. 
더 자세한 내용과 예제 코드는,Microsoft Scripting Site  사이트를 참고하시기 바랍니다. 

VBScript Matches 컬렉션 개체
앞에서 말했듯이, Matches 컬렉션 개체는 Execute 메소드를 실행한 경우에만 반환됩니다. 이 컬렉션 개체는 0개 이상의 Match 개체를 포함할 수 있으며, 이 개체의 속성은 읽기 전용입니다. 

속성  
Count  
Item  

Count -컬렉션 안에 있는 Match 개체의 개수를 나타내는 읽기 전용 값입니다. 
Item - Matches 컬렉션 개체에서 Match 개체를 임의로 액세스할 수 있게 만드는 읽기 전용 값입니다. For-Next 루프를 사용하면, Matches 컬렉션 개체에서 Match 개체를 순서대로 액세스할 수도 있습니다. 
더 자세한 내용과 예제 코드는, Microsoft Scripting Site  를 참고하시기 바랍니다. 

VBScript Match 개체
각 Mathes 개체에는 0개 이상의 Match 개체가 들어 있습니다. 이 Match 개체들은 정규 표현식을 사용했을 때 성공적으로 일치한 문자열을 나타냅니다. 이 개체의 속성은 읽기 전용이며 일치하는 각 문자열에 대한 정보를 저장합니다. 

속성  
FirstIndex  
Length  
Value  

FirstIndex - 원래 문자열 안에서 정규 표현식에 일치하는 문자열의 위치를 나타내는 읽기 전용 값입니다. 이 색인은 위치를 기록하는데 0 기준 오프셋(문장의 첫 위치가 0번째임을 뜻함)을 사용합니다. 
Length - 일치된 문자열의 전체 길이를 나타내는 읽기 전용 값입니다 
Value - 일치된 값이나 텍스트를 나타내는 읽기 전용 값입니다. 이 값은Match 개체를 액세스할 때 사용되는 기본 값이기도 합니다. 
더 자세한 내용과 예제 코드는, Microsoft Scripting Site  를 참고하시기 바랍니다. 

패턴은 어떤 형태인가?
자, 지금까지는 이 모든 것이 지나치게 훌륭하고 환상적인 것으로 느껴지셨겠지만 실제는 어떨까요? 정규 표현식은 그 자체가 하나의 언어라고 할 수 있지만, Perl에 익숙한 사용자들이라면 누구나 쉽게 사용할 수 있습니다. VBScript는 Perl로부터 패턴 셋을 유도하기 때문에, 주요 기능도 Perl과 비슷합니다. 그러면, 정규 표현식을 정의하는 데 사용되는 패턴 셋 몇 가지를 살펴보도록 합시다. 패턴 셋은 여러 범주와 영역으로 분류할 수 있습니다. 

포지션 매칭

포지션 매칭은 ^와 $(을)를 사용하여 문자열의 시작이나 끝을 검색합니다. 패턴 속성을 "^VBScript"로 설정할 경우, "VBScript is cool."에는 일치하지만, "I like VBScript."에는 일치하지 않습니다. 

기호 기능 
^  문자열의 시작만 비교합니다

"^A"는 "An A+ for Anita."의 첫번째 "A"를 비교합니다.  
$  문자열의 끝을 비교합니다.

"t$"는 "A cat in the hat"의 마지막 "t"를 비교합니다.  
\b  임의의 워드 영역을 비교합니다

"ly\B"는 "possibly tomorrow."의 "ly"를 비교합니다  
\B  Matches any non-word boundary

 


리터럴

리터럴은 영숫자 문자, ASCII, 8진수 문자, 16진수 문자, UNICODE, 또는 특수 구분 문자 등을 모두 총칭하는 말입니다. 특별한 의미를 갖고 있는 몇몇 문자는 구분해야 합니다. 이들 특수 문자를 비교하려면, 정규 표현식을 문자 앞에 \를 사용해야 합니다. 

기호 기능 
영숫자  영문자와 숫자를 비교합니다.  
\n  새로운 라인을 비교합니다  
\f  용지 공급을 비교합니다  
\r  캐리지 리턴을 비교합니다.  
\t  가로 탭을 비교합니다.  
\v  수평 탭을 비교합니다.  
\?  ?(을)를 비교합니다.  
\*  *(을)를 비교합니다.  
\+  +(을)를 비교합니다.  
\.  . (을)를 비교합니다.  
\|  |(을)를 비교합니다.  
\{  {(을)를 비교합니다.  
\}  }(을)를 비교합니다.  
\\  \(을)를 비교합니다.  
\[  [(을)를 비교합니다.  
\]  ] (을)를 비교합니다.  
\(  ((을)를 비교합니다.  
\)  ) (을)를 비교합니다.  
\xxx  8진수 xxx로 표시된 ASCII 문자를 비교합니다.

"\50"은 "(" 또는 chr (40) (을)를 비교합니다.  
\xdd  16진수 dd로 표시된 ASCII 문자를 비교합니다.

"\x28"은 "(" 또는 chr (40) (을)를 비교합니다.  
\uxxxx  UNICODE xxxx로 표시된 ASCII 문자를 비교합니다.

"\u00A3"은 "&pound;"를 비교합니다.  

문자 클래스 

문자 클래스를 사용하면 괄호 [] 안에 식을 삽입하여 사용자에 의해 정의된 그룹을 만들 수 있습니다. 문자 클래스의 문자들을 제외한 나머지 문자들을 사용하려면 [] 안에 ^(을)를 첫번째 문자로 삽입해야 합니다. 또한, 문자의 범위를 지정할 때는 대시를 사용합니다. 예를 들어, 정규 표현식 "[^a-zA-Z0-9]"(은)는 영문자와 숫자를 제외한 모든 문자를 비교합니다. 추가로 구분 문자와 리터럴로 묶인 문자셋도 있습니다. 


기호 기능 
[xyz]  문자셋 안에 포함되어 있는 임의의 한 문자를 비교합니다.

"[a-e]" (은)는 "basketball" 안의 "b"를 비교합니다.  
[^xyz]  문자 셋 안에 포함되어 있지 않은 임의의 한 문자를 비교합니다.

"[^a-e]"는 "basketball" 안의 "s"를 비교합니다.  
.  \n을 제외한 임의의 문자를 비교합니다.  
\w  임의의 워드 문자를 비교합니다. 
[a- zA-Z_0-9]와 동일함.  
\W  워드 문자를 제외한 임의의 문자를 비교합니다. 
[^a-zA-Z_0-9]와 동일함.  
\d  임의의 숫자를 비교합니다. [0-9].  
\D  숫자를 제외한 임의의 문자를 비교합니다. 
[^0-9]와 동일함.  
\s  임의의 공백 문자를 비교합니다.
[ \t\r\n\v\f]와 동일함.  
\S  공백 문자가 아닌 임의의 문자를 비교합니다.
[^ \t\r\n\v\f]와 동일함.  

반복

반복 매칭을 사용하면 정규 표현식 안에 있는 특정 절에 대한 검색을 여러 번 수행할 수 있습니다. 반복 매칭에서는 어떤 요소가 정규 표현식 안에서 몇 번 반복될 것인지를 지정할 수 있습니다. 

기호 기능  
{x}  {x} 정규 표현식을 x번 비교합니다.

"\d{5}"는 5개의 숫자를 비교합니다.  
(x,}  정규 표현식을 x번 이상 비교합니다.

"\s{2,}"는 최소한 두 개의 공백 문자를 비교합니다  
{x,y}  정규 표현식을 x부터 y번까지 비교합니다. 

"\d{2,3}"는 2개 이상 3개 미만의 숫자를 비교합니다. .  
?  0번 또는 한 번 비교합니다. {0,1}와 동일함.

"a\s?b"는 "ab" 또는 "a b"를 비교합니다.  
*  0번 이상 비교합니다. {0,}와 동일함.  
+  한번 이상 비교합니다.{1,}과 동일함.  


교체와 그룹핑

교체와 그룹핑은 보다 복잡한 정규 표현식을 만들 때 사용합니다. 교체와 그룹핑 기술은 정규 표현식 안에 복잡한 절을 만들고, 보다 많은 융통성과 제어 능력을 제공합니다. 

기호 기능  
()  절을 그룹핑하여 절을 만듭니다. 중첩하여 사용할 수도 있습니다. 

"(ab)?(c)"는 "abc" 또는 "c"를 비교합니다.  
|  교체는 여러 절을 하나의 정규 표현식으로 조합한 다음 개별적인 절을 비교합니다. 

"(ab)|(cd)|(ef)"는 "ab" 또는 "cd" 또는 "ef"를 비교합니다.  

역방향 참조

프로그래머는 역방향 참조를 통해 정규 표현식의 일부를 다시 참조할 수 있습니다. 그 방법은 괄호와 백슬레시(\) 뒤에 한 개의 숫자를 사용하는 것입니다. 첫 번째 괄호 절은 \1로 참조되고 두 번째 괄호 절은 \2로 참조되는 식입니다. 

기호 기능  
()\n  왼쪽 괄호에 있는 표현식을 n번 반복해서 문장을 비교합니다. 

"(\w+)\s+\1"는 "hubba hubba" 같이, 한 열 안에서 두 번 나타나는 임의의 워드를 비교합니다.."  

예제로 확인하기!
이 예제는 지금까지 설명한 것을 적용한 것으로, 정규 표현식을 이용하여 유효한 입력 값이 입력되어 있는지 검사하는 간단한 응용 프로그램입니다. 사용자가 유효한 값을 입력할 때까지 사용자에게 입력을 요구하는 프롬프트가 반복적으로 나타납니다. 먼저 초기 패턴을 자세히 설명하겠습니다. 

"^\s*((\$\s?)|(&pound;\s?))?((\d+(\.(\d\d)?)?)|(\.\d\d))\s*(UK|GBP|GB|USA|US|USD)?)\s*$" 

"^\s*…" 와 "…\s*$" - 앞과 뒤에 몇 개의 공백 문자든지 올 수 있음을 나타내며, 입력은 반드시 라인 자체 위에 있어야 합니다. 
"((\$\s?)|(?\s?))?" - 옵션 공백 앞에 오는 옵션 $ 또는 £ 기호를 나타냅니다.. 
"((\d+(\.(\d\d)?)?)|(\.\d\d))" - 생략 가능한 십진수 소수점 2자리 또는 십진수 소수점 2 자리수 앞에 오는 한 자리 이상의 숫자를 찾습니다. 이 말은 6., 23.33, .88와 같은 숫자는 사용 가능하나 5.5는 사용할 수 없음을 의미합니다. 
"\s*(UK|GBP|GB|USA|US|USD)?" - 문자열에 대하여 생략 및 사용이 가능하고 인수 앞에서 유효한 공백 문자의 수를 의미합니다. 
본 예제의 경우, 정규 표현식은 사용자의 US 달러 또는 영국 파운드 입력 여부를 결정하는 데 사용됩니다. 필자는 £, UK, GBP, 또는 GB 문자열을 검색하고 있습니다. 정규 표현식 결과가 참이면 사용자는 영국 파운드 단위의 액수를 입력한 것이라고 보면 됩니다. 그렇지 않다면 USD 통화를 사용한 것이겠지요. 

이 코드를 사용하려면 코드를 CurrencyEx.vbs로 저장하고 Windows Script Host를 이용해 코드를 실행시킨 다음 VB에 복사하거나(이 경우, Microsoft VBScript 정규 표현식에 참조를 추가할 필요가 있음) HTML 파일에 코드를 포함시킵니다.

Sub CurrencyEx
Dim inputstr, re, amt
Set re = new regexp  'Create the RegExp object

'Ask the user for the appropriate information
inputstr = inputbox("I will help you convert USA and CAN currency. Please enter the amount to convert:")
'Check to see if the input string is a valid one.
re.Pattern = "^\s*((\$\s?)|(&pound;\s?))?((\d+(\.(\d\d)?)?)|(\.\d\d))\s*(UK|GBP|GB|USA|US|USD)?)\s*$"
re.IgnoreCase = true
do while re.Test(inputstr) <> true
'Prompt for another input if inputstr is not valid
inputstr = inputbox("I will help you convert USA and GBP currency. Please enter the amount to(USD or GBP):")

loop
'Determine if we are going from GBP->US or USA->GBP
re.Pattern = "&pound;|UK|GBP|GB"
if re.Test(inputstr) then
'The user wants to go from GBP->USD
 
re.Pattern = "[a-z$&pound; ]"
re.Global = True
amt = re.Replace(inputstr, "")
amt = amt * 1.6368
amt = cdbl(cint(amt * 100) / 100)
amt = "$" & amt
else
'The user wants to go from USD->GBP

re.Pattern = "[a-z$&pound; ]"
re.Global = True
amt = re.Replace(inputstr, "")
amt = amt * 0.609
amt = cdbl(cint(amt * 100) / 100)
amt = "&pound;" & amt
end if

msgbox ("Your amount of: " & vbTab & inputstr & vbCrLf & "is equal to: " & vbTab & amt)
End sub


더욱 강력한 파워를!
Visual Basic 개발자들이 정규 표현식을 사용할 수 있도록 VBScript 정규 표현식 엔진은 COM 개체로 구현되어 왔습니다. 이 경우, 정규 표현식은 보다 강력한 힘을 발휘하게 되는데 즉, Visual Basic 또는 C와 같은 VBScript 외의 다양한 소스로부터 호출이 가능하기 때문입니다. 예컨대, 필자는 Outlook(R) 97, Outlook 98 또는 Outlook 2000의 접속 목록을 통해 내용을 추적하고 특정 도시에 사는 접속자 이름을 반환하는 작은 Visual Basic 응용 프로그램을 만든 경험이 있습니다. 

이 프로그램은 매우 간단합니다. 먼저 사용자는 검색할 대상 도시명을 입력하고, 구분 표시에는 쉼표를 사용합니다. 그런 다음, Outlook에 작성할 새 접속 폴더의 이름을 입력합니다. 각 접속이 일치하면 이 내용은 새로 작성된 접속 폴더에 복사됩니다. 

Microsoft VBScript 정규 표현식 개체 라이브러리에 참조를 추가할 경우 몇 가지 유용한 조기 바인딩 기능(early binding)을 사용할 수 있습니다. 이 조기 바인딩 개체는 몇 가지 이점을 제공하는데 즉, 속도가 빠르고 코딩 프로그램 사용이 간편하다는 점입니다. "new RegExp"가 즉시 사용되므로 사용자는 개체에 참조를 추가하고 VBScript코드를 오려내어 VB에 그대로 붙일 수 있습니다. 

이러한 이유로 필자 또한 정규 표현식과 동일한 방법을 사용하여 Outlook 9.0 개체 라이브러리를 참조한 적이 있습니다. 물론, 여러분은 여전히 CreateObject() (을)를 사용하여 COM 호출을 생성시킬 수도 있으나 상기 방법을 더 간편하게 사용할 수 있을 것입니다. 이 개체들을 작성한 후 간단한 코드를 사용하여 도시명과 일치하는 폴더와 트리를 액세스할 수 있습니다. 본인은 2개의 모음 개체를 가지는 작은 도움 함수 compareCollectionObjects(x,y)(을)를 사용/비교하여 일치 여부를 확인합니다. 

이 프로그램을 사용하려면 단순히 코드를 VB(참조 추가에 필요함)에 복사한 다음 FindCityContacts() 함수를 호출하면 됩니다. . 


Sub FindCityContacts()

    Dim strTemp
    Dim index
    Dim citySearch
    Dim myNameSpace, myContacts, newCityContacts, newCityContactsName
    Dim contact
    Dim newContact

    'Set the early binding objects
    Dim re as New RegExp  
    Dim myApp as New Outlook.Application

    re.Global = True
    re.IgnoreCase = True

    citySearch = InputBox("Please enter the cities of your search, separated by commas.")
    newCityContactsName = InputBox("Please enter the new contact folder name")

    'Set some of the objects and create the new Contacts folder
    Set myNameSpace = myApp.GetNamespace("MAPI")
    'olFolderContacts = 10
    Set myContacts = myNameSpace.GetDefaultFolder(10)   
    Set newCityContacts = myContacts.Folders.Add(newCityContactsName)

    'Set cities, using regular expressions to contain the city names
    re.Pattern = "[^,]+"
    Set cities = re.Execute(citySearch)
    For Each city In cities

       'Set citytokens to be the individual tokens in the city name
       'Then we compare them to the address tokens in each contact
        re.Pattern = "[^ ]+"
        Set citytokens = re.Execute(city)

        For i = 1 to myContacts.Items.Count
            re.Pattern = "[^ ]+"
            Set contact = myContacts.Items.Item(i)

            Set HomeAddressCityTokens = re.Execute(contact.HomeAddressCity)
            If compareCollectionObjects(HomeAddressCityTokens, citytokens) = 1 Then

                Set newContact = contact.Copy
                newContact.Move newCityContacts
            End If

            Set OtherAddressCityTokens = re.Execute(contact.OtherAddressCity)
            If compareCollectionObjects(OtherAddressCityTokens, citytokens) = 1 Then
                Set newContact = contact.Copy
                newContact.Move newCityContacts
            End If

            Set BusinessAddressCityTokens = re.Execute(contact.BusinessAddressCity)
            If compareCollectionObjects(BusinessAddressCityTokens, citytokens) = 1 Then
                Set newContact = contact.Copy
                newContact.Move newCityContacts
            End If
        Next
    Next

MsgBox "done"

End Sub

'This function is provided as a helper-function 
' to compare two collection objects.
Function compareCollectionObjects(x, y)

    Dim index
    Dim flag
    flag = 1

    If x.Count <> y.Count Then
        flag = 0
    Else
        index = x.Count

        For i = 0 To (index - 1)
            If StrComp(x.Item(i), y.Item(i), 1) Then
                flag = 0
            End If
        Next
    End If

    compareCollectionObjects = flag

End Function


넘치는 정보!
앞에서 보았듯이, Microsoft는 정규 표현식(버전 5.0)을 이용하여 VBSscript를 강화시키는데, 이것은 VBScript와 Jscript 비교에서 가장 중요한 부분이었습니다. 스크립팅 엔진 버전 5.0에서 우리는 VBScript의 기능을 향상시키는 데 특히 비중을 두었습니다. 이제 여러분은 정규 표현식을 추가시킴으로써 데이터를 보다 확실하게 관리하고 그 효과를 높일 수 있게 되었으며, 클라이언트와 서버에서 보다 강력한 웹 응용 프로그램을 만들 수 있게 되었습니다.